Шаг 95.
Задачи ComputerScience на Python. Простейшие нейронные сети. Задачи классификации. Классический набор данных радужной оболочки

    На этом шаге мы рассмотрим использование созданной нейронной сети для классификации ирисов.

    Подобно существованию классических задач информатики, существуют и классические наборы данных для машинного обучения. Они используются для проверки новых методов и сравнения их с существующими. А также служат хорошей отправной точкой для тех, кто изучает машинное обучение. Возможно, самым известным является набор данных об ирисах. Собранный в 1930-х годах, этот набор данных состоит из 150 образцов ирисов (красивые цветы), разделенных на три вида по 50 растений в каждом. Для всех растений измерены четыре атрибута: длина чашелистика, ширина чашелистика, длина лепестка и ширина лепестка.

    Стоит отметить: нейронной сети безразлично, что представляют собой атрибуты. С точки зрения важности ее модель обучения не делает различий между длиной чашелистика и длиной лепестка. Если такое различие должно быть сделано, то пользователю нейронной сети следует выполнить соответствующую корректировку.

    Имеется файл с данными, разделенными запятыми (в формате CSV), который содержит набор данных об ирисах. Этот набор получен из репозитория машинного обучения UCI Калифорнийского университета: Lichman М. UCI Machine Learning Repository. Irvine, CA: University of California, School of Information and Computer Science, 2013, http://archive.ics.uci.edu/. CSV-файл - это просто текстовый файл со значениями, разделенными запятыми. Это общий формат обмена табличными данными, включая электронные таблицы.

    Вот несколько строк из файла iris.csv:

5.1,3.5,1.4,0.2,Iris-setosa
4.9,3.0,1.4,0.2,Iris-setosa
4.7,3.2,1.3,0.2,Iris-setosa
4.6,3.1,1.5,0.2,Iris-setosa
5.0,3.6,1.4,0.2,Iris-setosa

    Каждая строка описывает отдельную единицу данных. Четыре числа представляют собой четыре атрибута (длина и ширина чашелистика, длина и ширина лепестка), которые, с нашей точки зрения, являются произвольными в отношении того, что они на самом деле представляют. Название в конце каждой строки соответствует определенному виду ириса. Все пять строк относятся к одному и тому же виду - данный образец был взят из верхней части файла, и три вида сгруппированы вместе по 50 строк в каждом.

    Для того чтобы прочитать с диска CSV-файл, используем несколько функций из стандартной библиотеки Python. Модуль csv поможет прочитать данные в структурированном виде. Встроенная функция ореn() создает объект файла, который передается в csv.reader(). Помимо этих нескольких строк остальная часть приведенного ниже текста просто переупорядочивает данные из CSV-файла, чтобы подготовить их к применению нашей сетью для обучения и проверки.

import csv
from typing import List
from util import normalize_by_feature_scaling
from network import Network
from random import shuffle

if __name__ == "__main__":
    iris_parameters: List[List[float]] = []
    iris_classifications: List[List[ float ]] = []
    iris_species: List[str] = []
    with open('iris.csv', mode='r') as iris_file:
        irises: List = list(csv.reader(iris_file))
        shuffle(irises)  # получаем наши строки данных в случайном порядке
        for iris in irises:
            parameters: List[float] = [float(n) for n in iris[0:4]]
            iris_parameters.append(parameters)
            species: str = iris[4]
            if species == "Iris-setosa":
                iris_classifications.append([1.0, 0.0, 0.0])
            elif species == "Iris-versicolor":
                iris_classifications.append([0.0, 1.0, 0.0])
            else:
                iris_classifications.append([0.0, 0.0, 1.0])
            iris_species.append(species)
    normalize_by_feature_scaling(iris_parameters)

    Значение iris_parameters представляет собой коллекцию из четырех атрибутов для каждого образца. Используем эту коллекцию для классификации каждого ириса. iris_classif ication - это фактическая классификация любого образца. В нашей нейронной сети будет три выходных нейрона, каждый из которых соответствует одному из возможных видов. Например, окончательный набор выходных данных [0,9, 0,3, 0,1] будет означать классификацию Iris-setosa, поскольку этому виду соответствует первый нейрон и он выдал наибольшее число.

    Мы уже знаем правильные ответы для обучения, поэтому у каждого ириса есть готовый ответ. Для цветка, который должен иметь тип Iris-setosa, запись в iris_ classification будет иметь вид [1.0, 0.0, 0.0]. Эти значения станут использоваться для расчета ошибки после каждого этапа обучения. В iris_species хранятся непосредственные соответствия классификаций для каждого цветка на английском языке. Ирис вида iris-setosa будет отмечен в наборе данных как "Iris-setosa".


Отсутствие блока проверки ошибок делает этот код весьма опасным. Он не подходит для практической работы, но вполне пригоден для тестовых целей.

    Теперь определим саму нейронную сеть.

    iris_network: Network = Network([4, 6, 3], 0.3)

    Аргумент layer_structure определяет сеть с тремя слоями (одним входным, одним скрытым и одним выходным) с параметрами [4, 6, 3]: входной слой имеет четыре нейрона, скрытый - шесть, а выходной - три. Четыре нейрона входного слоя соответствуют четырем параметрам, используемым для классификации каждого образца. Три нейрона выходного слоя соответствуют непосредственно трем разным видам, к которым мы стремимся отнести каждый входной элемент. Шесть нейронов скрытого слоя являются скорее результатом проб и ошибок, чем некоей формулой. То же самое относится и к learning_rate. Эти два значения (количество нейронов в скрытом слое и скорость обучения) могут быть получены экспериментально, если точность сети окажется ниже оптимальной. Листинг 7.16. irisjest.py (продолжение)

    def iris_interpret_output(output: List[float]) -> str:
        if max(output) == output[0]:
            return "Iris-setosa"
        elif max(output) == output[1]:
            return "Iris-versicolor"
        else:
            return "Iris-virginica"

    iris_interpret_output() - служебная функция, которая передается методу сети validate() для определения правильных классификаций.

    Наконец сеть готова к обучению:

    # обучение для первых 140 ирисов из набора данных, и так 50 раз
    iris_trainers: List[List[float]] = iris_parameters[0:140]
    iris_trainers_corrects: List[List[float]] = iris_classifications[0:140]
    for _ in range(50):
        iris_network.train(iris_trainers, iris_trainers_corrects)

    Обучаем сеть на первых 140 ирисах из набора данных, который состоит из 150 ирисов. Напомним, что строки, прочитанные из CSV-файла, были перетасованы. Это гарантирует, что при каждом запуске программы сеть обучается на разных подмножествах набора данных. Обратите внимание на то, что мы обучаем сеть 50 раз на 140 ирисах. Изменение этого значения сильно влияет на количество времени, которое потребуется на обучение нейронной сети. Как правило, чем дольше обучение, тем точнее будет работать нейронная сеть. Финальным тестом станет проверка правильности классификации последних десяти ирисов из набора данных:

    # тест на последних десяти ирисах из набора данных
    iris_testers: List[List[float]] = iris_parameters[140:150]
    iris_testers_corrects: List[str] = iris_species[140:150]
    iris_results = iris_network.validate(iris_testers, iris_testers_corrects, 
                                         iris_interpret_output)
    print(f"{iris_results[0]} корректно из {iris_results[1]} = {iris_results[2] * 100}%")
Архив с текстом программы и файлом с данными можно взять здесь.

    Вся работа сводится к этому последнему вопросу: сколько из десяти случайно выбранных из набора данных ирисов будут правильно классифицированы нейронной сетью? Поскольку начальные веса каждого нейрона определялись случайным образом, разные прогоны могут давать разные результаты. Можете попробовать настроить скорость обучения, количество скрытых нейронов и количество итераций обучения, чтобы сделать сеть более точной.

    В итоге вы должны увидеть такой результат:

9 корректно из 10 = 90.0%

    На следующем шаге мы разберем еще один пример.




Предыдущий шаг Содержание Следующий шаг