Самая простая нейронная сеть на Python. Программирование питон нейросеть


Основы Python – Нейронные сети

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

Материал рассчитан на людей, не знакомых с языками программирования.

Для начала Python надо установить. Затем нужно поставить удобную среду для написания программ на Python. Этим двум шагам посвящена отдельная статья на портале.

Если все установлено и настроено, можно начинать.

Поехали!

Переменные

Переменная — ключевое понятие в любом языке программирования (и не только в них). Проще всего представить переменную в виде коробки с ярлыком. В этой коробке хранится что-то (число, матрица, объект, …) представляющее для нас ценность.

Например, мы хотим создать переменную x, которая должна хранить значение 10. В Python код создания этой переменной будет выглядеть так:

x = 10

Слева мы объявляем переменную с именем x. Это равносильно тому, что мы приклеили на коробку именной ярлык. Далее идет знак равенства и число 10. Знак равенства здесь играет необычную роль. Он не означает, что «x равно 10». Равенство в данном случае кладет число 10 в коробку. Если говорить более корректно, то мы присваиваем переменной x число 10.

Теперь, в коде ниже мы можем обращаться к этой переменной, также выполнять с ней различные действия.

Можно просто вывести значение этой переменной на экран:

x=10 print(x)

Надпись print(x) представляет собой вызов функции. Их мы будем рассматривать далее. Сейчас важно то, что эта функция выводит в консоль то, что расположено между скобками. Между скобками у нас стоит x. Ранее мы присвоили x значение 10. Именно 10 и выводится в консоли, если вы выполните программу выше.

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

x = 2 y = 3 # Сложение z = x + y print(z) # 5 # Разность z = x - y print(z) # -1 # Произведение z = x * y print(z) # 6 # Деление z = x / y print(z) # 0.66666... # Возведение в степень z = x ** y print(z) # 8

В коде выше мы вначале создаем две переменные, содержащие 2 и 3. Затем создаем переменную z, которая хранит результат операции с x и y и выводит результаты в консоль. На этом примере хорошо видно, что переменная может менять свое значение в ходе выполнения программы. Так, наша переменная z меняет свое значение аж 5 раз.

Функции

Иногда возникает необходимость много раз выполнять одни и те же действия. Например, в нашем проекте нужно часто выводить 5 строчек текста.

«Это очень важный текст!»«Этот текст нильзя ни прочитать»«Ошибка в верхней строчке допущена специально»«Привет и пока»«Конец»

Наш код будет выглядеть так:

x = 10 y = x + 8 - 2 print("Это очень важный текст!") print("Этот текст нильзя не прочитать") print("Ошибка в верхней строчке допущена специально") print("Привет и пока") print("Конец") z = x + y print("Это очень важный текст!") print("Этот текст нильзя не прочитать") print("Ошибка в верхней строчке допущена специально") print("Привет и пока") print("Конец") test = z print("Это очень важный текст!") print("Этот текст нильзя не прочитать") print("Ошибка в верхней строчке допущена специально") print("Привет и пока") print("Конец")

Выглядит все это очень избыточно и неудобно. Кроме того, во второй строчке допущена ошибка. Ее можно исправить, но исправлять придется сразу в трех местах. А если у нас в проекте эти пять строчек вызываются 1000 раз? И все в разных местах и файлах?

Специально для случаев, когда необходимо часто выполнять одни и те же команды, в языках программирования можно создавать функции.

Функция — отдельный блок кода, который можно вызывать по имени.

Задается функция с помощью ключевого слова def . Далее следует название функции, затем скобки и двоеточие. Дальше с отступом надо перечислить действия, которые будут выполнены при вызове функции.

def print_5_lines(): print("Это очень важный текст!") print("Этот текст нильзя не прочитать") print("Ошибка в верхней строчке допущена специально") print("Привет и пока") print("Конец")

Теперь мы определили функцию print_5_lines(). Теперь, если в нашем проекте нам в очередной раз надо вставить пять строчек, то мы просто вызываем нашу функцию. Она автоматически выполнит все действия.

# Определяем функцию def print_5_lines(): print("Это очень важный текст!") print("Этот текст нильзя не прочитать") print("Ошибка в верхней строчке допущена специально") print("Привет и пока") print("Конец") # Код нашего проекта x = 10 y = x + 8 - 2 print_5_lines() z = x + y print_5_lines() test = z print_5_lines()

Удобно, не правда ли? Мы серьезно повысили читаемость кода. Кроме того, функции хороши еще и тем, что если вы хотите изменить какое-то из действий, то достаточно подправить саму функцию. Это изменение будет работать во всех местах, где вызывается ваша функция. То есть мы можем исправить ошибку во второй строчке выводимого текста («нильзя» > «нельзя») в теле функции. Правильный вариант автоматически будет вызываться во всех местах нашего проекта.

Функции с параметрами

Просто повторять несколько действий конечно удобно. Но это еще не все. Иногда мы хотим передать какую-ту переменную в нашу функцию. Таким образом, функция может принимать данные и использовать их в процессе выполнения команд.

Переменные, которые мы передаем в функцию, называются аргументами.

Напишем простую функцию, которая складывает два данных ей числа и возвращает результат.

def sum(a, b): result = a + b return result

Первая строчка выглядит почти так же, как и обычные функции. Но между скобок теперь находятся две переменные. Это параметры функции. Наша функция имеет два параметра (то есть принимает две переменные).

Параметры можно использовать внутри функции как обычные переменные. На второй строчке мы создаем переменную result, которая равна сумме параметров a и b. На третьей строчке мы возвращаем значение переменной  result.

Теперь, в дальнейшем коде мы можем писать что-то вроде:

new = sum(2, 3) print(new)

Мы вызываем функцию sum и по очереди передаем ей два аргумента: 2 и 3. 2 становится значением переменной a, а 3 становится значением переменной b. Наша функция возвращает значение (сумму 2 и 3), и мы используем его для создания новой переменной new.

Запомните. В коде выше числа 2 и 3 — аргументы функции sum. А в самой функции  sum переменные a и b — параметры. Другими словами, переменные, которые мы передаем функции при ее вызове называются аргументами. А вот внутри функции эти переданные переменные называются параметрами. По сути, это два названия одного и того же, но путать их не стоит.

Рассмотрим еще один пример. Создадим функцию square(a), которая принимает какое-то одно число и возводит его в квадрат:

def square(a): return a * a

Наша функция состоит всего из одной строчки. Она сразу возвращает результат умножения параметра a на a.

Я думаю вы уже догадались, что вывод данных в консоль мы тоже производим с помощью функции. Эта функция называется print() и она выводит в консоль переданный ей аргумент: число, строку, переменную.

Массивы

Если переменную можно представлять как коробку, которая что-то хранит (не обязательно число), то массивы можно представить в виде книжных полок. Они содержат сразу несколько переменных. Вот пример массива из трех чисел и одной строки:

array = [1, 89, 3, "строка"]

Вот и пример, когда переменная содержит не число, на какой-то другой объект. В данном случае, наша переменная содержит массив. Каждый элемент массива пронумерован. Попробуем вывести какой-нибудь элемент массива:

array = [1, 89, 3, "строка"] print( array[1] )

В консоли вы увидите число 89. Но почему 89, а не 1? Все дело в том, что в Python, как и во многих других языках программирования, нумерация массивов начинается с 0. Поэтому array[1] дает нам второй элемент массива, а не первый. Для вызова первого надо было написать array[0].

Размер массива

Иногда бывает очень полезно получить количество элементов в массиве. Для этого можно использовать функцию len(). Она сама подсчитает количество элементов и вернет их число.

array = [1, 89, 3, "строка"] print( len(array) )

В консоли выведется число 4.

Условия и циклы

По умолчанию любые программы просто подряд выполняют все команды сверху вниз. Но есть ситуации, когда нам необходимо проверить какое-то условие, и в зависимости от того, правдиво оно или нет, выполнить разные действия.

Кроме того, часто возникает необходимость много раз повторить практически одинаковую последовательность команд.

В первой ситуации помогают условия, а во второй — циклы.

Условия

Условия нужны для того, чтобы выполнить два разных набора действий в зависимости от того, истинно или ложно проверяемое утверждение.

В Python условия можно записывать с помощью конструкции if: ... else: .... Пусть у нас есть некоторая переменная x = 10. Если x меньше 10, то мы хотим разделить x на 2. Если же x больше или равно 10, то мы хотим создать другую переменную new, которая равна сумме x и числа 100. Вот так будет выглядеть код:

x = 10 if(x < 10): x = x / 2 print(x) else: new = x + 100 print(new)

После создания переменной x мы начинаем записывать наше условие.

Начинается все с ключевого слова if (в переводе с английского «если»). В скобках мы указываем проверяемое выражение. В данном случае мы проверяем, действительно ли наша переменная x меньше 10. Если она действительно меньше 10, то мы делим ее на 2 и выводит результат в консоль.

Затем идет ключевое слово else, после которого начинается блок действий, которые будут выполнены, если выражение в скобках после if ложное.

Если она больше или равна 10, то мы создаем новую переменную new, которая равна x + 100 и тоже выводим ее в консоль.

Циклы

Циклы нужны для многократного повторения действий. Предположим, мы хотим вывести таблицу квадратов первых 10 натуральных чисел. Это можно сделать так.

print("Квадрат 1 равен " + str(1**2)) print("Квадрат 2 равен " + str(2**2)) print("Квадрат 3 равен " + str(3**2)) print("Квадрат 4 равен " + str(4**2)) print("Квадрат 5 равен " + str(5**2)) print("Квадрат 6 равен " + str(6**2)) print("Квадрат 7 равен " + str(7**2)) print("Квадрат 8 равен " + str(8**2)) print("Квадрат 9 равен " + str(9**2)) print("Квадрат 10 равен " + str(10**2))

Пусть вас не удивляет тот факт, что мы складываем строки. «начало строки» + «конец» в Python означает просто соединение строк: «начало строкиконец». Так же и выше мы складываем строку «Квадрат x равен » и преобразованный с помощью функции str(x**2) результат возведения числа во 2 степень.

Выглядит код выше очень избыточно. А что, если нам надо вывести квадраты первых 100 чисел? Замучаемся выводить…

Именно для таких случаев и существуют циклы. Всего в Python 2 вида циклов:  while и for. Разберемся с ними по очереди.

Цикл while повторяет необходимые команды до тех пор, пока остается истинным условие.

x = 1 while x <= 100: print("Квадрат числа " + str(x) + " равен " + str(x**2)) x = x + 1

Сначала мы создаем переменную и присваиваем ей число 1. Затем создаем цикл while и проверяем, меньше (или равен) ли 100 наш x. Если меньше (или равен) то мы выполняем два действия:

  1. Выводим квадрат x
  2. Увеличиваем x на 1

После второй команды программа возвращается к условию. Если условие снова истинно, то мы снова выполняем эти два действия. И так до тех пор, пока x не станет равным 101. Тогда условие вернет ложь и цикл больше не будет выполняться.

Цикл for предназначен для того, чтобы перебирать массивы. Запишем тот же пример с квадратами первой сотни натуральных чисел, но уже через цикл for.

for x in range(1,101): print("Квадрат числа " + str(x) + " равен " + str(x**2))

Разберем первую строку. Мы используем ключевое слово for для создания цикла. Далее мы указываем, что хотим повторить определенные действия для всех x в диапазоне от 1 до 100. Функция range(1,101) создает массив из 100 чисел, начиная с 1 и заканчивая 100.

Вот еще пример перебора массива с помощью цикла for:

for i in [1, 10, 100, 1000]: print(i * 2)

Код выше выводит 4 цифры: 2, 20, 200 и 2000. Тут наглядно видно, как берет каждый элемент массива и выполняет набор действий. Затем берет следующий элемент и повторяет тот же набор действий. И так пока элементы в массиве не кончатся.

Классы и объекты

В реальной жизни мы оперируем не переменными или функциями, а объектами. Ручка, машина, человек, кошка, собака, самолет — объекты. Теперь начнем подробно рассматривать кошку.

Она обладает некоторыми параметрами. К ним относятся цвет шерсти, цвет глаз, ее кличка. Но это еще не все. Помимо параметров, кошка может выполнять различные действия: мурлыкать, шипеть и царапаться.

Только что мы схематически описали всех кошек в целом. Подобное описание свойств и действий какого-то объекта (например, кошки) на языке Python и называется классом. Класс — просто набор переменных и функций, которые описывают какой-то объект.

Важно понимать разницу между классом и объектом. Класс — схема, которая описывает объект. Объект — ее материальное воплощение. Класс кошки — описание ее свойств и действий. Объект кошки и есть сама реальная кошка. Может быть много разных реальных кошек — много объектов-кошек. Но класс кошки только один. Хорошей демонстрацией служит картинка ниже:

 

Классы

Для создания класса (схемы нашей кошки) надо написать ключевое слово class и затем указать имя этого класса:

class Cat:

Дальше нам нужно перечислить действия этого класса (действия кошки). Действия, как вы могли уже догадаться, представляют собой функции, определенные внутри класса. Такие функции внутри класса принято называть методами.

Метод — функция, определенная внутри класса.

Словесно мы уже описали методы кошки выше: мурлыкать, шипеть, царапаться. Теперь сделаем это на языке Python.

# Класс кошки class Cat: # Мурлыкать def purr(self): print("Муррр!") # Шипеть def hiss(self): print("Кшшш!") # Царапаться def scrabble(self): print("Царап-царап!")

Вот так все просто! Мы взяли и определили три обычные функции, но только внутри класса.

Для того, чтобы разобраться с непонятным параметром self, добавим еще один метод нашей кошке. Этот метод будет разом вызывать все три уже созданных метода.

# Класс кошки class Cat: # Мурлыкать def purr(self): print("Муррр!") # Шипеть def hiss(self): print("Кшшш!") # Царапаться def scrabble(self): print("Царап-царап!") # Все вместе def all_in_one(self): self.purr() self.hiss() self.scrabble()

Как видите, обязательный для любого метода параметр self позволяет нам обращаться к методами и переменным самого класса! Без этого аргумента выполнить подобные действия мы бы не смогли.

Давайте теперь зададим свойства нашей кошки (цвет шерсти, цвет глаз, кличка). Как это сделать? В абсолютно любом классе можно определить функцию __init__(). Эта функция всегда вызывается, когда мы создаем реальный объект нашего класса.

# Класс кошки class Cat: # Действия, которые надо выполнять при создании объекта "Кошка" def __init__(self, wool_color, eyes_color, name): self.wool_color = wool_color self.eyes_color = eyes_color self.name = name # Мурлыкать def purr(self): print("Муррр!") # Шипеть def hiss(self): print("Кшшш!") # Царапаться def scrabble(self): print("Царап-царап!") # Все вместе def all_in_one(self): self.purr() self.hiss() self.scrabble()

В выделенном выше методе __init__() мы задаем переменные нашей кошки. Как мы это делаем? Сначала мы передаем в этот метод 3 аргумента, отвечающие за цвет шерсти, цвет глаз и кличку. Затем, мы используем параметр self для того, чтобы при создании объекта сразу задать нашей кошки 3 описанных выше атрибута.

Что означает эта строчка?

self.wool_color = wool_color

В левой части мы создаем атрибут для нашей кошки с именем wool_color, а дальше мы присваиваем этому атрибуту значение, которое содержится в параметре wool_color, который мы передали в функцию __init__(). Как видите, строчка выше не отличается от обычного создания переменной. Только приставка self указывает на то, что эта переменная относится к классу Cat.

Атрибут — переменная, которая относится к какому-то классу.

Итак, мы создали готовый класс кошки. Вот его код:

# Класс кошки class Cat: # Действия, которые надо выполнять при создании объекта "Кошка" def __init__(self, wool_color, eyes_color, name): self.wool_color = wool_color self.eyes_color = eyes_color self.name = name # Мурлыкать def purr(self): print("Муррр!") # Шипеть def hiss(self): print("Кшшш!") # Царапаться def scrabble(self): print("Царап-царап!") # Все вместе def all_in_one(self): self.purr() self.hiss() self.scrabble()

Объекты

Мы создали схему кошки. Теперь давайте создадим по этой схеме реальный объект кошки:

my_cat = Cat("черный", "зеленые", "Зося")

В строке выше мы создаем переменную my_cat, а затем присваиваем ей объект класса Cat. Выглядит все этот как вызов некоторой функции Cat(...). На самом деле так и есть. Этой записью мы вызываем метод __init__() класса Cat. Функция __init__() в нашем классе принимает 4 аргумента: сам объект класса self, который указывать не надо, а также еще 3 разных аргумента, которые затем становятся атрибутами нашей кошки.

Итак, с помощью строчки выше мы создали реальный объект кошки. Наша кошка имеет следующие атрибуты: черную шерсть, зеленые глаза и кличку Зося. Давайте выведем эти атрибуты в консоль:

print(my_cat.wool_color) print(my_cat.eyes_color) print(my_cat.name)

То есть обратиться к атрибутам объекта мы можем, записав имя объекта, поставив точку и указав имя желаемого атрибута.

Атрибуты кошки можно менять. Например, давайте сменим кличку нашей кошки:

my_cat.name = "Нюша"

Теперь, если вы вновь выведете в консоль имя кошки, то вместо Зоси увидите Нюшу.

Напомню, что класс нашей кошки позволяет ей выполнять некоторые действия. Если мы погладим нашу Зосю/Нюшу, то она начнет мурлыкать:

my_cat.purr()

Выполнение данной команды выведет в консоль текст «Муррр!». Как видите, обращаться к методам объекта так же просто, как и обращаться к его атрибутам.

Модули

Любой файл с расширением .py является модулем. Даже тот, в котором вы отрабатываете эту статью. Зачем они нужны? Для удобства. Очень много людей создают файлы с полезными функциями и классами. Другие программисты подключают эти сторонние модули и могут использовать все определенные в них функции и классы, тем самым упрощая себе работу.

Например, вам не нужно тратить время и писать свои функции для работы с матрицами. Достаточно подключить модуль numpy и использовать его функции и классы.

На данный момент другие Python программисты написали уже свыше 110 000 разнообразных модулей. Упоминавшийся выше модуль numpy позволяет быстро и удобно работать с матрицами и многомерными массивами. Модуль math предоставляет множество методов для работы с числами: синусы, косинусы, переводы градусов в радианы и прочее и прочее…

Установка модуля

Python устанавливается вместе со стандартным набором модулей. В этот набор входит очень большое количество модулей, которые позволяют работать с математикой, web-запросами, читать и записывать файлы и выполнять другие необходимые действия.

Если вы хотите использовать модуль, который не входит в стандартный набор, то вам потребуется установить его. Для установки модуля откройте командую строку (Win + R, затем введите в появившемся поле «cmd») и введите в нее команду:

pip install [название_модуля]

Начнется процесс установки модуля. Когда он завершится, вы можете спокойно использовать установленный модуль в своей программе.

Подключение и использование модуля

Сторонний модуль подключается очень просто. Надо написать всего одну короткую строку кода:

import [название_модуля]

Например, для импорта модуля, позволяющего работать с математическими функциями, надо написать следующее:

import math

Как обратиться к функции модуля? Надо написать название модуля, затем поставить точку и написать название функции/класса. Например, факториал 10 находится так:

math.factorial(10)

То есть мы обратились к функции factorial(a), которая определена внутри модуля  math. Это удобно, ведь нам не нужно тратить время и вручную создавать функцию, которая считает факториал числа. Можно подключить модуль и сразу выполнить необходимое действие.

neuralnet.info

Нейросеть в 11 строчек на Python / Хабр

О чём статья
Лично я лучше всего обучаюсь при помощи небольшого работающего кода, с которым могу поиграться. В этом пособии мы научимся алгоритму обратного распространения ошибок на примере небольшой нейронной сети, реализованной на Python.
Дайте код!
X = np.array([ [0,0,1],[0,1,1],[1,0,1],[1,1,1] ]) y = np.array([[0,1,1,0]]).T syn0 = 2*np.random.random((3,4)) - 1 syn1 = 2*np.random.random((4,1)) - 1 for j in xrange(60000): l1 = 1/(1+np.exp(-(np.dot(X,syn0)))) l2 = 1/(1+np.exp(-(np.dot(l1,syn1)))) l2_delta = (y - l2)*(l2*(1-l2)) l1_delta = l2_delta.dot(syn1.T) * (l1 * (1-l1)) syn1 += l1.T.dot(l2_delta) syn0 += X.T.dot(l1_delta)

Слишком сжато? Давайте разобьём его на более простые части.

Часть 1: Небольшая игрушечная нейросеть
Нейросеть, тренируемая через обратное распространение (backpropagation), пытается использовать входные данные для предсказания выходных.Вход Выход 0 0 1 0 1 1 1 1 1 0 1 1 0 1 1 0

Предположим, нам нужно предсказать, как будет выглядеть колонка «выход» на основе входных данных. Эту задачу можно было бы решить, подсчитав статистическое соответствие между ними. И мы бы увидели, что с выходными данными на 100% коррелирует левый столбец.

Обратное распространение, в самом простом случае, рассчитывает подобную статистику для создания модели. Давайте попробуем.

Нейросеть в два слоя
import numpy as np # Сигмоида def nonlin(x,deriv=False): if(deriv==True): return f(x)*(1-f(x)) return 1/(1+np.exp(-x)) # набор входных данных X = np.array([ [0,0,1], [0,1,1], [1,0,1], [1,1,1] ]) # выходные данные y = np.array([[0,0,1,1]]).T # сделаем случайные числа более определёнными np.random.seed(1) # инициализируем веса случайным образом со средним 0 syn0 = 2*np.random.random((3,1)) - 1 for iter in xrange(10000): # прямое распространение l0 = X l1 = nonlin(np.dot(l0,syn0)) # насколько мы ошиблись? l1_error = y - l1 # перемножим это с наклоном сигмоиды # на основе значений в l1 l1_delta = l1_error * nonlin(l1,True) # !!! # обновим веса syn0 += np.dot(l0.T,l1_delta) # !!! print "Выходные данные после тренировки:" print l1 Выходные данные после тренировки: [[ 0.00966449] [ 0.00786506] [ 0.99358898] [ 0.99211957]]

Переменные и их описания.

X — матрица входного набор данных; строки – тренировочные примеры y – матрица выходного набора данных; строки – тренировочные примеры l0 – первый слой сети, определённый входными данными l1 – второй слой сети, или скрытый слой syn0 – первый слой весов, Synapse 0, объединяет l0 с l1. "*" — поэлементное умножение – два вектора одного размера умножают соответствующие значения, и на выходе получается вектор такого же размера "-" – поэлементное вычитание векторов x.dot(y) – если x и y – это вектора, то на выходе получится скалярное произведение. Если это матрицы, то получится перемножение матриц. Если матрица только одна из них – это перемножение вектора и матрицы.

И это работает! Рекомендую перед прочтением объяснения поиграться немного с кодом и понять, как он работает. Он должен запускаться прямо как есть, в ipython notebook. С чем можно повозиться в коде:

Разберём код по строчкам
import numpy as np

Импортирует numpy, библиотеку линейной алгебры. Единственная наша зависимость.

def nonlin(x,deriv=False):

Наша нелинейность. Конкретно эта функция создаёт «сигмоиду». Она ставит в соответствие любое число значению от 0 до 1 и преобразовывает числа в вероятности, а также имеет несколько других полезных для тренировки нейросетей свойств.

image

if(deriv==True):

Эта функция также умеет выдавать производную сигмоиды (deriv=True). Это одно из её полезных свойств. Если выход функции – это переменная out, тогда производная будет out * (1-out). Эффективно.

X = np.array([ [0,0,1], …

Инициализация массива входных данных в виде numpy-матрицы. Каждая строка – тренировочный пример. Столбцы – это входные узлы. У нас получается 3 входных узла в сети и 4 тренировочных примера.

y = np.array([[0,0,1,1]]).T

Инициализирует выходные данные. ".T" – функция переноса. После переноса у матрицы y есть 4 строки с одним столбцом. Как и в случае входных данных, каждая строка – это тренировочный пример, и каждый столбец (в нашем случае один) – выходной узел. У сети, получается, 3 входа и 1 выход.

np.random.seed(1)

Благодаря этому случайное распределение будет каждый раз одним и тем же. Это позволит нам проще отслеживать работу сети после внесения изменений в код.

syn0 = 2*np.random.random((3,1)) – 1

Матрица весов сети. syn0 означает «synapse zero». Так как у нас всего два слоя, вход и выход, нам нужна одна матрица весов, которая их свяжет. Её размерность (3, 1), поскольку у нас есть 3 входа и 1 выход. Иными словами, l0 имеет размер 3, а l1 – 1. Поскольку мы связываем все узлы в l0 со всеми узлами l1, нам требуется матрица размерности (3, 1).

Заметьте, что она инициализируется случайным образом, и среднее значение равно нулю. За этим стоит достаточно сложная теория. Пока просто примем это как рекомендацию. Также заметим, что наша нейросеть – это и есть эта самая матрица. У нас есть «слои» l0 и l1, но они представляют собой временные значения, основанные на наборе данных. Мы их не храним. Всё обучение хранится в syn0.

for iter in xrange(10000):

Тут начинается основной код тренировки сети. Цикл с кодом повторяется многократно и оптимизирует сеть для набора данных.

l0 = X

Первый слой, l0, это просто данные. В X содержится 4 тренировочных примера. Мы обработаем их все и сразу – это называется групповой тренировкой [full batch]. Итого мы имеем 4 разных строки l0, но их можно представить себе как один тренировочный пример – на этом этапе это не имеет значения (можно было загрузить их 1000 или 10000 без всяких изменений в коде).

l1 = nonlin(np.dot(l0,syn0))

Это шаг предсказания. Мы позволяем сети попробовать предсказать вывод на основе ввода. Затем мы посмотрим, как это у неё получается, чтобы можно было подправить её в сторону улучшения.

В строке содержится два шага. Первый делает матричное перемножение l0 и syn0. Второй передаёт вывод через сигмоиду. Размерности у них следующие:

(4 x 3) dot (3 x 1) = (4 x 1)

Матричные умножения требуют, чтобы в середине уравнения размерности совпадали. Итоговая матрица имеет количество строк, как у первой, а столбцов – как у второй.

Мы загрузили 4 тренировочных примера, и получили 4 догадки (матрица 4х1). Каждый вывод соответствует догадке сети для данного ввода.

l1_error = y - l1

Поскольку в l1 содержатся догадки, мы можем сравнить их разницу с реальностью, вычитая её l1 из правильного ответа y. l1_error – вектор из положительных и отрицательных чисел, характеризующий «промах» сети.

l1_delta = l1_error * nonlin(l1,True)

А вот и секретный ингредиент. Эту строку нужно разбирать по частям.

Первая часть: производная

nonlin(l1,True)

l1 представляет три этих точки, а код выдаёт наклон линий, показанных ниже. Заметьте, что при больших значениях вроде x=2.0 (зелёная точка) и очень малые, вроде x=-1.0 (фиолетовая) линии имеют небольшой уклон. Самый большой угол у точки х=0 (голубая). Это имеет большое значение. Также отметьте, что все производные лежат в пределах от 0 до 1.

image

Полное выражение: производная, взвешенная по ошибкам

l1_delta = l1_error * nonlin(l1,True)

Математически существуют более точные способы, но в нашем случае подходит и этот. l1_error – это матрица (4,1). nonlin(l1,True) возвращает матрицу (4,1). Здесь мы поэлементно их перемножаем, и на выходе тоже получаем матрицу (4,1), l1_delta.

Умножая производные на ошибки, мы уменьшаем ошибки предсказаний, сделанных с высокой уверенностью. Если наклон линии был небольшим, то в сети содержится либо очень большое, либо очень малое значение. Если догадка в сети близка к нулю (х=0, у=0,5), то она не особенно уверенная. Мы обновляем эти неуверенные предсказания и оставляем в покое предсказания с высокой уверенностью, умножая их на величины, близкие к нулю.

syn0 += np.dot(l0.T,l1_delta)

Мы готовы к обновлению сети. Рассмотрим один тренировочный пример. В нём мы будем обновлять веса. Обновим крайний левый вес (9.5)

image

weight_update = input_value * l1_delta

Для крайнего левого веса это будет 1.0 * l1_delta. Предположительно, это лишь незначительно увеличит 9.5. Почему? Поскольку предсказание было уже достаточно уверенным, и предсказания были практически правильными. Небольшая ошибка и небольшой наклон линии означает очень небольшое обновление.

image

Но поскольку мы делаем групповую тренировку, указанный выше шаг мы повторяем для всех четырёх тренировочных примеров. Так что это выглядит очень похоже на изображение вверху. Так что же делает наша строчка? Она подсчитывает обновления весов для каждого веса, для каждого тренировочного примера, суммирует их и обновляет все веса – и всё одной строкой.

Понаблюдав за обновлением сети, вернёмся к нашим тренировочным данным. Когда и вход, и выход равны 1, мы увеличиваем вес между ними. Когда вход 1, а выход – 0, мы уменьшаем вес.

Вход Выход 0 0 1 0 1 1 1 1 1 0 1 1 0 1 1 0

Таким образом, в наших четырёх тренировочных примерах ниже, вес первого входа по отношению к выходу будет постоянно увеличиваться или оставаться постоянным, а два других веса будут увеличиваться и уменьшаться в зависимости от примеров. Этот эффект и способствует обучению сети на основе корреляций входных и выходных данных.

Часть 2: задачка посложнее
Вход Выход 0 0 1 0 0 1 1 1 1 0 1 1 1 1 1 0

Попробуем предсказать выходные данные на основе трёх входных столбцов данных. Ни один из входных столбцов не коррелирует на 100% с выходным. Третий столбец вообще ни с чем не связан, поскольку в нём всю дорогу содержатся единицы. Однако и тут можно увидеть схему – если в одном из двух первых столбцов (но не в обоих сразу) содержится 1, то результат также будет равен 1.

Это нелинейная схема, поскольку прямого соответствия столбцов один к одному не существует. Соответствие строится на комбинации входных данных, столбцов 1 и 2.

Интересно, что распознавание образов является очень похожей задачей. Если у вас есть 100 картинок одинакового размера, на которых изображены велосипеды и курительные трубки, присутствие на них определённых пикселей в определённых местах не коррелирует напрямую с наличием на изображении велосипеда или трубки. Статистически их цвет может казаться случайным. Но некоторые комбинации пикселей не случайны – те, что формируют изображение велосипеда (или трубки).

imageimage

Стратегия
Чтобы скомбинировать пиксели в нечто, у чего может появиться однозначное соответствие с выходными данными, нужно добавить ещё один слой. Первый слой комбинирует вход, второй назначает соответствие выходу, используя в качестве входных данных выходные данные первого слоя. Обратите внимание на таблицу.Вход (l0) Скрытые веса (l1) Выход (l2) 0 0 1 0.1 0.2 0.5 0.2 0 0 1 1 0.2 0.6 0.7 0.1 1 1 0 1 0.3 0.2 0.3 0.9 1 1 1 1 0.2 0.1 0.3 0.8 0

Случайным образом назначив веса, мы получим скрытые значения для слоя №1. Интересно, что у второго столбца скрытых весов уже есть небольшая корреляция с выходом. Не идеальная, но есть. И это тоже является важной частью процесса тренировки сети. Тренировка будет только усиливать эту корреляцию. Она будет обновлять syn1, чтобы назначить её соответствие выходным данным, и syn0, чтобы лучше получать данные со входа.

Нейросеть в три слоя
import numpy as np def nonlin(x,deriv=False): if(deriv==True): return f(x)*(1-f(x)) return 1/(1+np.exp(-x)) X = np.array([[0,0,1], [0,1,1], [1,0,1], [1,1,1]]) y = np.array([[0], [1], [1], [0]]) np.random.seed(1) # случайно инициализируем веса, в среднем - 0 syn0 = 2*np.random.random((3,4)) - 1 syn1 = 2*np.random.random((4,1)) - 1 for j in xrange(60000): # проходим вперёд по слоям 0, 1 и 2 l0 = X l1 = nonlin(np.dot(l0,syn0)) l2 = nonlin(np.dot(l1,syn1)) # как сильно мы ошиблись относительно нужной величины? l2_error = y - l2 if (j% 10000) == 0: print "Error:" + str(np.mean(np.abs(l2_error))) # в какую сторону нужно двигаться? # если мы были уверены в предсказании, то сильно менять его не надо l2_delta = l2_error*nonlin(l2,deriv=True) # как сильно значения l1 влияют на ошибки в l2? l1_error = l2_delta.dot(syn1.T) # в каком направлении нужно двигаться, чтобы прийти к l1? # если мы были уверены в предсказании, то сильно менять его не надо l1_delta = l1_error * nonlin(l1,deriv=True) syn1 += l1.T.dot(l2_delta) syn0 += l0.T.dot(l1_delta) Error:0.496410031903 Error:0.00858452565325 Error:0.00578945986251 Error:0.00462917677677 Error:0.00395876528027 Error:0.00351012256786
Переменные и их описания
X — матрица входного набор данных; строки – тренировочные примеры y – матрица выходного набора данных; строки – тренировочные примеры l0 – первый слой сети, определённый входными данными l1 – второй слой сети, или скрытый слой l2 – финальный слой, это наша гипотеза. По мере тренировки должен приближаться к правильному ответу syn0 – первый слой весов, Synapse 0, объединяет l0 с l1. syn1 – второй слой весов, Synapse 1, объединяет l1 с l2. l2_error – промах сети в количественном выражении l2_delta – ошибка сети, в зависимости от уверенности предсказания. Почти совпадает с ошибкой, за исключением уверенных предсказаний l1_error – взвешивая l2_delta весами из syn1, мы подсчитываем ошибку в среднем/скрытом слое l1_delta – ошибки сети из l1, масштабируемые по увеернности предсказаний. Почти совпадает с l1_error, за исключением уверенных предсказаний

Код должен быть достаточно понятным – это просто предыдущая реализация сети, сложенная в два слоя один над другим. Выход первого слоя l1 – это вход второго слоя. Что-то новое есть лишь в следующей строке.

l1_error = l2_delta.dot(syn1.T)

Использует ошибки, взвешенные по уверенности предсказаний из l2, чтобы подсчитать ошибку для l1. Получаем, можно сказать, ошибку, взвешенную по вкладам – мы подсчитываем, какой вклад в ошибки в l2 вносят значения в узлах l1. Этот шаг и называется обратным распространением ошибок. Затем мы обновляем syn0, используя тот же алгоритм, что и в варианте с нейросетью из двух слоёв.

habr.com

Простая нейросеть на Python | Pythono.ru

Простая нейросеть на Python

Простая нейросеть на Python

Многие хотят написать свою нейросеть, но теряются в тоннах книг по машинному обучению, и сложных математических формулах. Сегодня я покажу вам относительно простой пример нейросети на Python, который работает просто и понятно. Есть множество разных видов нейросетей, и целей для которых они служат. В общем случае схема работы нейросети такова: - Создают программу используя библиотеки для построения нейросетей - Обучают программу на БОЛЬШОМ наборе данных, то есть дают ей набор данных, правильно размеченный человеком, чтобы нейросеть обучилась и начала работать на других похожих наборах данных - Сохраняют и используют обученную нейросеть Я в своем примере совместил обучение нейросети вместе с ее тестированием, поэтому при каждом запуске нейросеть сперва обучается(что занимает некоторое время, не думайте что программа зависла). Если вы захотите использовать данный пример в своих проектах то разделите скрипт на две части - первая будет обучать модель и сохранять её, а вторая работать на основе уже сохраненной модели. Подробнее о сохранении и загрузке моделей можно почитать тут https://machinelearningmastery.com/save-load-machine-learning-models-python-scikit-learn/ К тому же в моем примере я буду использовать очень маленький набор данных, в реальных проектах набор данных должен быть минимум из нескольких тысяч строк. Итак, мы создадим нейросеть которая пытается угадать какой тип контента нужно найти для пользователя, в ответ на его вопрос. Например, если юзер спросит "Кто такой Виктор Цой", нейросеть должна ответить "Информация о личности". Она не будет отвечать на вопрос, просто классифицирует вопрос в определенную категорию. Обучающий набор данных очень маленький поэтому тестировать будем на более-менее похожих вопросах. Сперва создадим набор данных для обучения. У меня это обычный текстовый файл в котором лежат строки, разделенные значком @. Назовите файл 1.txt и киньте рядом со скриптом нейросети. Используйте кодировку UTF-8.

Что такое патока @ Информация о предмете Где живут медведи @ Местоположение Как зовут сына Трампа @ Имя Как зовут Мадонну @ Имя Как зовут Бьорк @ Имя Кто начал ядерную войну @ Имя Как зовут сына Сталина @ Имя Как зовут дочь Трампа @ Имя Почему небо голубое @ Информация о предмете Как сварить борщ @ Инструкция Как научиться летать @ Инструкция Как рано просыпаться @ Инструкция Как обрести счастье @ Инструкция Как найти парня @ Инструкция Как убить таракана @ Инструкция Сколько звезд на небе @ Количество Кто такая Мадонна @ Информация о личности Какая высота у Эйфелевой башни @ Количество Дата рождения Путина @ Дата рождения Когда началась вторая Мировая война @ Дата события Когда родился Майкл Джексон @ Дата рождения Почему идет дождь @ Информация о предмете В каких фильмах играл Ди Каприо @ Информация о предмете Когда родился Эйнштейн @ Дата рождения Когда началась Первая мировая война @ Дата В каком году был построен Титаник @ Дата Когда начал править Иван IV @ Дата Когда была битва под Аустерлицем @ Дата В каких годах была «Семилетняя война» @ Дата Когда начал править Наполеон Бонапарт @ Дата Когда закончилось правление Наполеона Бонапарта @ Дата В каких годах правил князь Святослав @ Дата В каком году умер Ярослав Мудрый @ Дата В каком году появляется первое упоминание о Москве @ Дата В каком году был основан Санкт-Петербург @ Дата Когда было Ледовое побоище @ Дата Когда была Куликовская битва @ Дата В каком году начали печатать книги на Руси @ Дата Когда была Полтавская битва @ Дата В каком году закончилась Первая мировая война @ Дата В каком году был заключен Тильзитский мир @ Дата В каком году были написаны «Отцы и дети» @ Дата Когда родился Вильгельм Фридрих Людвиг фон Пройсен @ Дата Когда отмечается День Учителя @ Дата Когда отмечается День Матери @ Дата Когда отменили крепостное право @ Дата Что произошло 12 июня 1812 @ Дата Что произошло 20 ноября 1805 @ Дата Что произошло 6 июня 1799 @ Дата Что произошло 1 апреля 1809 @ Дата Какой город начинает упоминатся с 1147 грода @ Дата Кто такой Эйнштейн @ Информация о личности Кто такие Eluveitie @ Информация о личности Что такое «дождь» @ Информация о предмете Кто основал Санкт-Петербург @ Имя Кто такой Христофор Колумб @ Информация о личности Как звали Колумба @ Имя Кто написал произведение «Преступление и наказание» @ Имя Кто написал стихотворение «Тройка» @ Имя Какой страной управляет королева Елизавета II @ Местоположение Какова средняя глубина Тихого океана @ Количество Какова высота Биг Бена @ Количество Где находится Сиднейская Опера @ Местоположение Где находится самое большое озеро @ Местоположение В какой стране столицей является город Москва @ Местоположение Теперь покажу сам скрипт нейросети для классификации вопросов. Я не буду подробно расписывать как установить через pip все нужные для нейросети модули. Скажу лишь что PyStemmer нужно скачать и установить в формате whl. Если у вас скрипт ругается на отсутствие какого-то модуля, ставьте модуль через pip. # -*- coding: utf-8 -*- import sys import numpy as np import pickle import re from Stemmer import Stemmer from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.linear_model import SGDClassifier from sklearn.pipeline import Pipeline from sklearn.metrics import accuracy_score # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # очистка текста с помощью regexp приведение слов в инфинитив и нижний регистр, замена цифр def text_cleaner(text): text = text.lower() # приведение в lowercase stemmer = Stemmer('russian') text = ' '.join( stemmer.stemWords( text.split() ) ) text = re.sub( r'\b\d+\b', ' digit ', text ) # замена цифр return text # - - - - - - - - - - - - - - - - - - - - - - - - - # загрузка данных из файла 1.txt # def load_data(): data = { 'text':[],'tag':[] } for line in open('1.txt'): if(not('#' in line)): row = line.split("@") data['text'] += [row[0]] data['tag'] += [row[1]] return data # - - - - - - - - - - - - - - - - - - - - - - - - - # Обучение нейросети def train_test_split( data, validation_split = 0.1): sz = len(data['text']) indices = np.arange(sz) np.random.shuffle(indices) X = [ data['text'][i] for i in indices ] Y = [ data['tag'][i] for i in indices ] nb_validation_samples = int( validation_split * sz ) return { 'train': { 'x': X[:-nb_validation_samples], 'y': Y[:-nb_validation_samples] }, 'test': { 'x': X[-nb_validation_samples:], 'y': Y[-nb_validation_samples:] } } # - - - - - - - - - - - - - - - - - - - - def openai(): data = load_data() D = train_test_split( data ) text_clf = Pipeline([ ('tfidf', TfidfVectorizer()), ('clf', SGDClassifier(loss='hinge')), ]) text_clf.fit(D['train']['x'], D['train']['y']) predicted = text_clf.predict( D['train']['x'] ) # Начало тестирования программы z=input("Введите вопрос без знака вопроса на конце: ") zz=[] zz.append(z) predicted = text_clf.predict( zz ) print(predicted[0]) # - - - - - - - - - - - - - - - - - - - - if __name__ == '__main__': sys.exit( openai() ) Давайте запустим нашу нейросеть, подождем пока она обучится (пару минут) и предложит нам ввести вопрос. Введем вопрос которого нет в обучающем файле - "Кто придумал ракету". Писать нужно без знака вопроса на конце. В ответ нейросеть выдаст "Имя", значит она определила что наш вопрос подразумевает ответ в котором должно быть чье-то имя. Заметьте, данного вопроса не было в файле 1.txt но нейросеть безошибочно определила что мы имеем ввиду, исходя из обучающей выборки. Данный классификатор очень прост. Вы можете подать на вход в файл 1.txt абсолютно любые данные которые нужно классифицировать, это не обязательно должны быть вопросы и их категории как в моем примере. Простая нейросеть на Python Иван Леднев Лого Pythono.ru Простая нейросеть на Python

pythono.ru

Установка Python и PyCharm – Нейронные сети

Нейронные сети надо писать на каком-то языке программирования. Их великое множество, но я рекомендую (и использую в учебнике и статьях) именно язык Python. Почему?

  1. Он очень прост в изучении
  2. Большое количество готовых библиотек
  3. Когда смотришь на программу, сразу видишь алгоритм, который она реализует
  4. Большая часть специалистов в машинном обучении используют Python и большая часть библиотек тоже создается именно под этот язык программирования

Скачивание и установка Python

Изначально компьютер не умеет работать с программным кодом, написанным на языке Python. Поэтому необходимо установить программу, которая будет выполнять созданные файлы — интерпретатор вместе со стандартной библиотекой.

Переходим на страницу загрузки и скачиваем последнюю версию Python (на рисунке выделено красным). Желтая кнопка справа предлагает скачать старую версию Python для Windows XP и ниже. Нам это не нужно, поэтому нажимаем на левую кнопку.

Запускаем скачанный .exe файл.

В первом открывшемся окне нас просят выбрать способ установки: простой и сложный. Сначала включите нижний флажок «Add Python 3.6 to PATH». Эта опция позволит вам использовать Python в любом месте через консоль.

Дальше выбирайте верхний (простой) способ установки.

 

Дальше начнется процесс установки:

По окончанию установки закрывайте окно установщика.

Теперь вы можете программировать на языке Python на вашем компьютере!

Скачивание и установка PyCharm

Ваш компьютер уже умеет работать с языком программирования Python. Сам программный код можно писать хоть в Блокноте, но это очень неудобно. Нам нужна умная среда, которая будет подсвечивать набираемый код и автоматически указывать на различные ошибки в нем.

Могу порекомендовать отличную и бесплатную среду — PyCharm от JetBrains. Эта компания специализируется на создании профессиональных сред для программирования. Если Microsoft Office практически всегда используется для работы с таблицами/презентациями и текстовыми документами, то программы от JetBrains занимают лидирующее положение среди программистов.

Итак, переходим на страницу скачивания PyCharm. Для скачивания доступно две версии: профессиональная и версия для сообщества. Версия для сообщества бесплатная. Ее и скачаем:

Запускаем скачанный .exe файл. В первом окне нас приветствует сам установщик. Смело кликаем «Next»:

Дальше надо указать место установки среды:

Важный момент! На следующем окне обязательно выделить галочку «Download and install JRE x86 by JetBrains», если у вас на компьютере не установлена Java. Если вы не знаете, что это такое, то лучше поставьте эту галочку 🙂 Также рекомендую отметить галочку «.py» для того, чтобы все файлы с программным кодом по умолчанию открывались в PyCharm. Это удобно.

Следующие окна можно смело пропустить и сразу перейти к процессу установки:

После окончания установки запускайте PyCharm. После красивого окна загрузки…

… появится стартовое окно программы. Если поверх стартового окна у вас выскочило второе маленькое окошко, то просто нажмите «OK». Создайте новый проект, кликнув на «Create New Project»:

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

Дальше откроется окно самого редактора.

Теперь вы готовы начать писать программы на Python!

Давайте проверим, как все работает. Для этого кликните правой кнопкой на название вашего проекта и в раскрывающемся списке выберите пункт «New > Python file»:

Появится окно, в котором вы можете задать имя файлу. Задайте какое-нибудь имя и нажмите «OK».

Справа откроется сам файл. Пока он пустой. Скопируйте в него следующий код:

print("Hello, World!")

Этот код выводит в консоль строку «Hello, World!».

Теперь нужно запустить нашу небольшую (1 строка) программу. Для этого в верхнем меню перейдите в «Run > Run…».

В появившемся окне щелкните по названию вашего файла. Теперь программа запустится. В нижней части редактора должна появиться консоль с результатом выполнения нашей программы:

Если ваш вывод похож на изображение выше, вы видите «Hello, World!» и никаких надписей красного цвета у вас не появилось, то поздравляю вас — установка всех программ прошла успешно и вы можете начинать нормально программировать на Python!

У меня ошибка!

Если у вас не устанавливается Python или PyCharm и выскакивают страшные окна с ошибками, если программа не выполняется, а консоль ругается на вас большими фразами с красным текстом… не паникуйте. Напишите о своей проблеме на форуме. Мы вам поможем 🙂

neuralnet.info

Python и нейронные сети | proft.me

python_nn.png

Искусственные нейронные сети (ИНС) — математические модели, а также их программные или аппаратные реализации, построенные по принципу организации и функционирования биологических нейронных сетей — сетей нервных клеток живого организма.

ИНС представляют собой систему соединённых и взаимодействующих между собой простых процессоров (искусственных нейронов).

Нейронные сети не программируются в привычном смысле этого слова, они обучаются. Возможность обучения — одно из главных преимуществ нейронных сетей перед традиционными алгоритмами. wikipedia

Содержание

  1. Основные свойства
  2. Решаемые проблемы
  3. Виды архитектур
  4. Правила обучения
  5. Функции активации
  6. Модули python для нейронных сетей
  7. Простой пример

Основные свойства

Нейронные сети были вдохновлены нашим собственным мозгом. Модель стандартного нейрона изобретена более пятидесяти лет назад и состоит из трех основных частей:

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

Биологический нейрон - сложная система, математическая модель которого до сих пор полностью не построена. Введено множество моделей, различающихся вычислительной сложностью и сходством с реальным нейроном. Одна из важнейших - формальный нейрон (ФН). Несмотря на простоту ФН, сети, построенные из таких нейронов, могут сформировать произвольную много мерную функцию на выходе (источник: Заенцев И. В. Нейронные сети: основные модели).

nn_fm.png

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

nn_f.png

где

Нейрон имеет несколько входных сигналов x и один выходной сигнал OUT. Параметрами нейрона, определяющими его работу, являются: вектор весов w, пороговый уровень θ и вид функции активации F.

Нейронные сети привлекают к себе внимание за счет следующих возможностей:

К основным свойствам нейронных сетей можно отнести:

  1. Способность обучаться. Нейронные сети не программируются, а обучаются на примерах. После предъявления входных сигналов (возможно, вместе с требуемыми выходами) сеть настраивают свои параметры таким образом, чтобы обеспечивать требуемую реакцию.

  2. Обобщение. Отклик сети после обучения может быть до некоторой степени нечувствителен к небольшим изменениям входных сигналов. Эта внутренне присущая способность "видеть"" образ сквозь шум и искажения очень важна для распознавания образов. Важно отметить, что искусственная нейронная сеть делает обобщения автоматически благодаря своей структуре, а не с помощью использования "человеческого интеллекта"" в форме специально написанных компьютерных программ.

  3. Параллелизм. Информация в сети обрабатывается параллельно, что позволяет достаточно выполнять сложную обработку данных с помощью большого числа простых устройств.

  4. Высокая надежность. Сеть может правильно функционировать даже при выходе из строя части нейронов, за счет того, что вычисления производятся локально и параллельно.

Алгоритм решения задач с помощью многослойного персептрона (источник: Заенцев И. В. Нейронные сети: основные модели)

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

Общий алгоритм решения:

  1. Определить, какой смысл вкладывается в компоненты входного вектора x. Входной вектор должен содержать формализованное условие задачи, т.е. всю информацию, необходимую для получения ответа.
  2. Выбрать выходной вектор y таким образом, чтобы его компоненты содержали полный ответ поставленной задачи.
  3. Выбрать вид нелинейности в нейронах (функцию активации). При этом желательно учесть специфику задачи, т.к. удачный выбор сократит время обучения.
  4. Выбрать число слоев и нейронов в слое.
  5. Задать диапазон изменения входов, выходов, весов и пороговых уровней, учитывая множество значений выбранной функции активации.
  6. Присвоить начальные значения весовым коэффициентам и пороговым уровням и дополнительным параметрам (например, крутизне функции активации, если она будет настраиваться при обучении). Начальные значения не должны быть большими, чтобы нейроны не оказались в насыщении (на горизонтальном участке функции активации), иначе обучение будет очень медленным. Начальные значения не должны быть и слишком малыми, чтобы выходы большей части нейронов не были равны нулю, иначе обучение также замедлится.
  7. Провести обучение, т.е. подобрать параметры сети так, чтобы задача решалась наилучшим образом. По окончании обучения сеть готова решить задачи того типа, которым она обучена.
  8. Подать на вход сети условия задачи в виде вектора x. Рассчитать выходной вектор y, который и даст формализованное решение задачи.

Решаемые проблемы

Проблемы решаемые с помощью нейронных сетей (источник).

  1. Классификация образов. Задача состоит в указании принадлежности входного образа (например, речевого сигнала или рукописного символа), представленного вектором признаков, одному или нескольким предварительно определенным классам. К известным приложениям относятся распознавание букв, распознавание речи, классификация сигнала электрокардиограммы, классификация клеток крови.

  2. Кластеризация/категоризация. При решении задачи кластеризации, которая известна также как классификация образов "без учителя", отсутствует обучающая выборка с метками классов. Алгоритм кластеризации основан на подобии образов и размещает близкие образы в один кластер. Известны случаи применения кластеризации для извлечения знаний, сжатия данных и исследования свойств данных.

  3. Аппроксимация функций. Предположим, что имеется обучающая выборка ((x1,y1), (x2,y2)..., (xn,yn)) (пары данных вход-выход), которая генерируется неизвестной функцией (x), искаженной шумом. Задача аппроксимации состоит в нахождении оценки неизвестной функции (x). Аппроксимация функций необходима при решении многочисленных инженерных и научных задач моделирования.

  4. Предсказание/прогноз. Пусть заданы n дискретных отсчетов {y(t1), y(t2)..., y(tn)} в последовательные моменты времени t1, t2,..., tn . Задача состоит в предсказании значения y(tn+1) в некоторый будущий момент времени tn+1. Предсказание/прогноз имеют значительное влияние на принятие решений в бизнесе, науке и технике. Предсказание цен на фондовой бирже и прогноз погоды являются типичными приложениями техники предсказания/прогноза.

  5. Оптимизация. Многочисленные проблемы в математике, статистике, технике, науке, медицине и экономике могут рассматриваться как проблемы оптимизации. Задачей алгоритма оптимизации является нахождение такого решения, которое удовлетворяет системе ограничений и максимизирует или минимизирует целевую функцию. Задача коммивояжера, относящаяся к классу NP-полных, является классическим примером задачи оптимизации.

  6. Память, адресуемая по содержанию. В модели вычислений фон Неймана обращение к памяти доступно только посредством адреса, который не зависит от содержания памяти. Более того, если допущена ошибка в вычислении адреса, то может быть найдена совершенно иная информация. Ассоциативная память, или память, адресуемая по содержанию, доступна по указанию заданного содержания. Содержимое памяти может быть вызвано даже по частичному входу или искаженному содержанию. Ассоциативная память чрезвычайно желательна при создании мультимедийных информационных баз данных.

  7. Управление. Рассмотрим динамическую систему, заданную совокупностью {u(t), y(t)}, где u(t) является входным управляющим воздействием, а y(t) - выходом системы в момент времени t. В системах управления с эталонной моделью целью управления является расчет такого входного воздействия u(t), при котором система следует по желаемой траектории, диктуемой эталонной моделью. Примером является оптимальное управление двигателем.

Виды архитектур

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

Классификация искусственных нейронных сетей по их архитектуре приведена на рисунке ниже.

Python и нейронные сети

Похожая классификация, но немного расширенная

Python и нейронные сети

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

Сравнительная таблица многослойного персепторна и RBF-сети

Многослойный персептрон RBF-сети
Граница решения представляет собой пересечение гиперплоскостей Граница решения - это пересечение гиперсфер, что задает границу более сложной формы
Сложная топология связей нейронов и слоев Простая 2-слойная нейронная сеть
Сложный и медленно сходящийся алгоритм обучения Быстрая процедура обучения: решение системы уравнений + кластеризация
Работа на небольшой обучающей выборке Требуется значительное число обучающих данных для приемлемого результат
Универсальность применения: кластеризация, аппроксимация, управление и проч Как правило, только аппроксимация функций и кластеризация

Рекуррентная сеть (сеть с обратными связями) - многослойная нейронная сеть, имеющая хотя бы один слой, выходные сигналы с которого поступают на этот же слой или на один из предыдущих слоев. В рекуррентной сети нейроны многократно участвуют в обработке каждой входной информации, что позволяет использовать некоторые динамические свойства нейросети. Использование обратных связей сокращает объем нейронной сети. На основе рекуррентных сетей разработаны различные модели ассоциативной памяти.

Сети прямого распространения (без обратных связей) Рекуррентные сети (с обратными связями)
Преимущества Простота реализации. Гарантированная (математически доказанная) сходимость вычислений. Меньший по сравнению с сетями прямого распространения объем сети(по количеству нейронов).
Недостатки Быстрый рост числа нейронов с увеличением сложности задачи. Необходимость использования дополнительных условий, обеспечивающих сходимость вычислений.

Искусственная нейронная сеть может рассматриваться как направленный граф со взвешенными связями, в котором искусственные нейроны являются узлами. По архитектуре связей искусственные нейронные сети могут быть сгруппированы в два класса: сети прямого распространения, в которых графы не имеют петель, и рекуррентные сети, или сети с обратными связями.

Сеть Хопфилда (адресуемая по содержанию ассоциативная память, модель Хопфилда) - нейронная сеть, состоящая из одного слоя нейронов, каждый из которых связан синапсами со всеми остальными нейронами, а также имеет один вход и один выход. Все нейроны используют жесткую пороговую функцию активации и могут давать на выходе два значения: -1 (заторможен) и +1 (возбужден).  В модели используется принцип хранения информации как динамически устойчивых аттракторов. В процессе настройки сети уменьшается энергетическая функция, достигая локального минимума (аттрактора), в котором энергетическая функция сохраняет постоянное значение.

Сети Хопфилда отличаются следующими признаками

Сеть Хемминга (Классификатор по минимуму расстояния Хемминга) - нейронная сеть ассоциативной памяти, принцип работы которой основан на вычислении расстояния Хемминга от входного вектора до всех векторов-образцов, известных сети. Сеть выбирает образец с наименьшим расстоянием Хемминга до входного вектора и выход, соответствующий этому образцу активизируется. Если сеть Хопфилда может восстанавливать зашумленные образы, то сеть Хемминга лишь указывает на соответствие входного образа одному из известных ей классов, а сам образ в ходе работы сети теряется.

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

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

Виды нейронных сетей и их характеристики (по материалам книги В. В. Круглов, В. В. Борисов - Искусственные нейронные сети. Теория и практика)

Название нейронной сети Область приминения Недостатки Преимущества
Искусственный резонанс - 1, ART-1 Network (Adaptive Resonance Theory Network - 1) Распознавание образов, кластерный анализ Неограниченное увеличение числа нейронов в процессе функционирования сети. При наличии шума возникает значительный проблемы, связанные с неконтролируемым ростом числа эталонов. Обучение без учителя
Двунаправленная ассоциативная память (ДАП). Bi-Directional Associative Memory (BAM) Ассоциативная память, распознавание образов. Емкость ДАП жестко ограниченна, также ДАП обладает некоторой непредсказуемостью в процессе функционирования. Возможны ложные ответы. По сравнению с автоассоциативной (например, с сетью Хопфилда), двунаправленная ассоциативная память дает возможность строить ассоциации между векторами X и Y, которые в общем случае имеют разные размерности. За счет таких возможностей гетероассоциативная память используется для более широкого класса приложений, чем автоассоциативная память. Процесс формирования синаптических весов является простым и достаточно быстрым. Сеть быстро сходиться в процессе функционирования.
Машина Больцмана (Boltzmann Machine) Распознавание образов, классификация. Медленный алгоритм обучения. Алгоритм дает возможность сети выбираться из локальных минимумов адаптивного рельефа.
Обратное распространение (Neural Network with Back Propagation Training Algorithm) Распознавание образов, классификация, прогнозирование, синтез речи, контроль, адаптивное управление, построение экспертных систем. Многокритериальная задача оптимизации в методе обратного распространения рассматривается как набор однокритериальных - на каждой итерации происходит изменения значений параметров сети, улучшающих работу лишь с одним примером обучающей выборки. Такой подход существенно уменьшает скорость обучения. Классический метод обратного распространения относиться к алгоритмам с линейной сходимостью. Для увеличения скорости сходимости необходимо использовать матрицы вторых производных функций ошибки. Обратное распространение - первый эффективный алгоритм обучения многослойных нейронных сетей. Один из самых популярных алгоритмом обучения, с его помощью решены и решаются многочисленных практические задачи.
Сесть встречного распространения (Counter Propagation Network) Распознавание и восстановление образов (ассоциативная память), сжатие данных (с потерями), статистический анализ. Сеть не дает возможность строить точные аппроксимации. В этом она значительно уступает сетям с обратным распространением ошибки. Слабая теоретическая проработка модификаций этой сети. Сеть встречного распространения проста. Она дает возможность извлекать статистические характеристики из множества входных сигналов. Сеть быстро обучается. Время ее обучения по сравнению с обратным распространением может быть в 100 раз меньше. Сеть полезна для приложений, в которых требуется быстрая начальная аппроксимация. Сеть дает возможность строить функции и обратную к ней, что находит применения при решении практических задач.
Delta Bar Delta сеть Распознавание образов, классификация. Стандартный алгоритм DBD не использует эвристики, основанные на моменте. Даже небольшое линейное увеличение коэффициентов может привести к значительному росту скорости обучения, что вызовет скачки в пространстве весов. Геометрическое уменьшение коэффициентов иногда оказывается недостаточно быстрым. Парадигма DBD является попыткой ускорить процесс конвергенции алгоритмов обратного распространения за счет использования дополнительное информации об изменении параметров и весов во время обучения.
Сеть поиска максимума с прямыми связями (Feed-Forward MAXNET) Совместно с сетью Хэмминга, в составе нейросетевых систем распознавания образов. Число слоев сети растет с увеличением размерности входного сигнала. В отличие от сети MAXNET циклического функционирования, в рассматриваемой модели заранее известен объем вычислений, который требуется для получения решения.
Гауссов классификатор (Neural Gaussian Classifier) Распознавание образов, классификация. Примитивные разделяющие поверхности (гиперплоскости) дают возможность решать лишь самые простые задачи распознавания. Считаются априорно известными распределениями входных сигналов, соответствующих разным классам. Программные или аппаратные реализации модели очень просты. Простой и быстрый алгоритм формирования синаптических весов и смещений.
Генетический алгоритм (Genetic Algorithm) Распознавание образов, классификация, прогнозирование. Сложные для понимания и программной реализации. ГА особенно эффективны в поиске глобальных минимумов адаптивных рельефов, так как ими исследуются большие области допустимых значений параметров нейронных сетей. Достаточно высокая скорость обучения, хотя и меньшая, чем скорость сходимости градиентных алгоритмов. ГА дают возможность оперировать дискретным значениями параметров нейронных сетей, что упрощает аппаратную реализацию нейронных сетей и приводит к сокращению общего времени обучения.
Сеть Хэмминга (Hamming Net) Распознавание образов, классификация, ассоциативная память, надежная передача сигналов в условиях помех Сеть способна правильно распознавать (классифицировать) только слабо зашумленные входные сигналы. Возможность использования только бинарных входных сигналов существенно ограничивает область применения Сеть работает предельно просто и быстро Выходной сигнал (решение задачи) формируется в результате прохода сигналов всего лишь через один слой нейронов Для сравнения: в многослойных сетях сигнал проходит через несколько слоев, в сетях циклического функционирования сигнал многократно проходит через нейроны сети, причем число итераций, необходимое для получения решения, бывает заранее не известно В модели использован один из самых простых алгоритмов формирования синаптических весов и смещений сети В отличие от сети Хопфилда, емкость сети Хэмминга не зависит от размерности входного сигнала, она в точности равна количеству нейронов. Сеть Хопфилда с входным сигналом размерностью 100 может запомнить 10 образцов, при этом у нее будет 10000 синапсов У сети Хэмминга с такой же емкостью будет всего лишь 1000 синапсов.
Сеть Хопфилда (Hopfield Network) Ассоциативная память, адресуемая по содержанию; распознавание образов; задачи оптимизации (в том числе, комбинаторной оптимизации). Сеть обладает небольшой емкостью. Кроме того, наряду с запомненными обрезами в сети хранятся и их 'негативы'. Размерность и тип входных сигналов совпадают с размерностью и типом выходных сигналов. Это существенно ограничивает применение сети в задачах распознавания образов. При использовании сильно коррелированных векторов-образцов возможно зацикливание сети в процессе функционирования. Квадратичные рост числе синапсов при увеличении размерности входного сигнала. Позволяет восстановить искаженные сигналы.
Входная звезда (Instsr) Может быть использована в сетях распознавания обрезов. Каждая заезда а отдельности реализует слишком простую функцию. Из таких звезд невозможно построить нейронную сеть, которая реализовала бы любое заданное отображение Это ограничивает практическое применение входных звезд. Входная заезда хорошо моделирует некоторые функции компонентов биологических нейронных сетей и может быть достаточна хорошей моделью отдельных участков мозга. При решении практических задач входные заезды могут быть использованы для построения простых быстро обучаемых сетей.
Сеть Кохонена (Kohonen's Neural Network) Кластерный анализ, распознавание образов, классификации. Сеть может быть использована для кластерного анализа только в случае, если заранее известно число кластеров. В отличие от сети ART, сеть Кохонена способна функционировать в условиях помех, так как число классов фиксировано, веса модифицируются медленно, и настройка весов заканчивается после обучения (в сети АВТ настройка продолжается непрерывно)
Сеть поиска максимума (MAXNET) Совместно с сетью Хэмминга, в составе нейросетевых систем распознавания образов. Заранее не известно число итераций функционирования нейронной сети MAXNET. Она определяет, какой из входных сигналов имеет максимальное значение. Однако, в процессе функционирования сеть не сохраняет само значение максимального сигнала. Квадратичный рост числа синапсов при увеличении размерности входного сигнала. Простата работы сети.
Выходная звезда (Outstsr) Может быть использована как компонент нейронных сетей для распознавания образов. Каждая звезда в отдельности реализует слишком простую функцию. Вычислительные возможности нейронных сетей, составленных из таких звезд, ограничены. При решении практических задач выходные заезды могут быть использованы для построения простых быстро обучаемых сетей.
Сеть радиального основания (Radial Basis Function Network) Распознавание образов, классификация. Заранее должно быть известно числа эталонов, а также эвристики для построения активационных функций нейронов скрытого слоя. Сети этого типа довольно компактны и быстро обучаются. Радиально базисная сеть обладает следующими особенностями: один скрытый слой, только нейроны скрытого слоя имеют нелинейную активационную функцию и синаптические веса входного и скрытого слоев равны единицы. Отсутствие этапа обучения в принятом смысле этого слова.
Нейронные сети, имитирующие отжиг (Neural Networks with Simulated Annealing Training Algorithm) С помощью алгоритма имитации отжита можно строить отображения векторов различной размерности. K построению таких отображений сводятся многие задачи распознавания образов, адаптивного управления, многопараметрической идентификации, прогнозирования и диагностики. Низкая скорость сходимости при обучении нейронных сетей большой размерности. "Тепловые флуктуации", заложенные в алгоритм, дают возможность избегать локальных минимумов. Показано, что алгоритм имитации отжига может быть использован для поиска глобального оптимума адаптивного рельефа нейронной сети.
Однослойный персептрон (Single Layer Perceptron) Распознавание образов, классификация. Простые разделяющие поверхности (гиперплоскости) дают возможность решать лишь несложные задачи распознавания. Программные или аппаратные реализации модели очень просты. Простой и быстрый алгоритм обучения.

Выбор количества нейронов и слоев (источник: Заенцев И. В. Нейронные сети: основные модели)

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

Количество нейронов и слоев связано:

  1. со сложностью задачи;
  2. с количеством данных для обучения;
  3. с требуемым количеством входов и выходов сети;
  4. с имеющимися ресурсами: памятью и быстродействием машины, на которой моделируется сеть;

Были попытки записать эмпирические формулы для числа слоев и нейронов, но применимость формул оказалась очень ограниченной.

Если в сети слишком мало нейронов или слоев:

  1. сеть не обучится и ошибка при работе сети останется большой;
  2. на выходе сети не будут передаваться резкие колебания аппроксимируемой функции y(x).

Превышение требуемого количества нейронов тоже мешает работе сети.

Если нейронов или слоев слишком много:

  1. быстродействие будет низким, а памяти потребуется много — на фон неймановских ЭВМ;
  2. сеть переобучится: выходной вектор будет передавать незначительные и несущественные де тали в изучаемой зависимости y(x), например, шум или ошибочные данные;
  3. зависимость выхода от входа окажется резко нелинейной: выходной вектор будет существен но и непредсказуемо меняться при малом изменении входного вектора x;
  4. сеть будет неспособна к обобщению: в области, где нет или мало известных точек функции y(x) выходной вектор будет случаен и непредсказуем, не будет адекватен решамой задаче.

Правила обучения

Существуют три парадигмы обучения: с учителем, без учителя (самообучение) и смешанная. В первом случае нейронная сеть располагает правильными ответами (выходами сети) на каждый входной пример. Веса настраиваются так, чтобы сеть производила ответы как можно более близкие к известным правильным ответам. Усиленный вариант обучения с учителем предполагает, что известна только критическая оценка правильности выхода нейронной сети, но не сами правильные значения выхода. Обучение без учителя не требует знания правильных ответов на каждый пример обучающей выборки.

Известны 4 основных типа правил обучения:

  1. коррекция по ошибке:
  2. машина Больцмана;
  3. правило Хебба;
  4. обучение методом соревнования;

Известные алгоритмы обучения (по материалам книги В. В. Круглов, В. В. Борисов - Искусственные нейронные сети. Теория и практика)

Парадигма Обучающие правило Архитектура нейронной сети Алгоритм обучения Задачи
С учителем Коррекция ошибок Однослойный и многослойный персептрон Алгоритмы обучения персептрона. Обратное распространение, Adaline и Madaline Классификация образов. Аппроксимация функций. Предсказание. Управление.
Больцман Рекурентная Алгоритм обучения Больцмана Классификация образов.
Хебб Многослойная прямого распространения Линейный дискриминантный анализ Анализ данных. Классификация образов.
Соревнование Соревнование Векторное квантование Категоризация внутри класса, сжатие данных
Сеть ART ART Map Классификация образов
Без учителя Коррекция ошибки Многослойная прямого распространения Проекция Саммона Категоризация внутри класса, сжатие данных. Анализ данных.
Хебб Прямого распространения или соревнование Метод главных компонентов Анализ данных. Сжатие данных
Сеть Хопфилда Обучение ассоциативной памяти Ассоциативная память
Соревнование Соревнование Векторное квантование Категоризация. Сжатие данных.
SOM Кохонена SOM Кохонена Категоризация. Анализ данных.
Сеть ART ART1, ART2 Категоризация
Смешанная Коррекция ошибки и соревнование Сеть RBFN Алгоритм обучения RBFN Классификация образов. Аппроксимация функций. Предсказание. Управление.

Сети, реализующие парадигму самообучения (без учителя), предназначены, как правило, для анализа внутренней латентной структуры входной информации и решают задачи автоматической классификации, кластеризации, факторного анализа, компрессии данных. Обучающий алгоритм подстраивает веса сети так чтобы предъявление достаточно близких входных векторов давало одинаковые выходы. Процесс обучения, следовательно, выделяет статистические свойства обучающего множества и группирует сходные векторы в классы.

Функции активации

Активационная функция (функция активации, функция возбуждения, характеристическая функция) - нелинейная функция, вычисляющая выходной сигнал формального нейрона (OUT). Обычно принимает в качестве аргумента сигнал, получаемый на выходе входного сумматора (NET). В качестве активационных часто используются функции: 

Жесткая пороговая функция

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

Линейный порог

Линейный порог - кусочно-линейная функция, используемая в качестве активационной функции в формальном нейроне. Как видно из рисунка, есть два линейных участка, где функция тождественно равна минимально допустимому и максимально допустимому значению и есть участок, на котором функция строго монотонно возрастает.

Сигмоидальная функция

Сигмоидальная функция (сигмоидная функция, сигмоид, сигмоида) - монотонно возрастающая всюду дифференцируемая S-образная нелинейная функция с насыщением, которую очень удобно использовать в формальном нейроне в качестве функции активации. Сигмоид позволяет усиливать слабые сигналы и не насыщаться от сильных сигналов. 

Среди однопараметрических наиболее распространены сигмоидальные функции следующих видов: 

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

Значение производной легко выражается через саму функцию. Быстрый расчет производной ускоряет обучение.

Гауссова кривая

Применяется в случаях, когда реакция нейрона должна быть максимальной для некоторого определенного значения NET.

Градиентное обучение - общий способ оптимизации нейронной сети, в котором минимизация функционала ошибки осуществляется по методу градиентного спуска. Примером градиентного обучения многослойного персептрона служит семейство методов обратного распространения ошибки.

Функция ошибок (функционал ошибок, функция ошибки) - целевая функция, требующая минимизации в процессе управляемого обучения нейронной сети.  Функция ошибок позволяет оценить качество работы нейронной сети во время обучения.

Подробнее с нейронными сетями можно познакомится по следующим ссылкам:

Модули python для нейронных сетей

Простой пример

В качестве примера приведу простую нейроную сеть (простой персептрон), которая после обучения сможет распознавать летающие объекты, не все, а только чайку :), все остальные входные образы будут распознаваться как НЛО.

# encoding=utf8 import random class NN: def __init__(self, threshold, size): """ Установим начальные параметры. """ self.threshold = threshold self.size = size self.init_weight() def init_weight(self): """ Инициализируем матрицу весов случайными данными. """ self.weights = [[random.randint(1, 10) for i in xrange(self.size)] for j in xrange(self.size)] def check(self, sample): """ Считаем выходной сигнал для образа sample. Если vsum > self.threshold то можно предположить, что в sample есть образ чайки. """ vsum = 0 for i in xrange(self.size): for j in xrange(self.size): vsum += self.weights[i][j] * sample[i][j] if vsum > self.threshold: return True else: return False def teach(self, sample): """ Обучение нейронной сети. """ for i in xrange(self.size): for j in xrange(self.size): self.weights[i][j] += sample[i][j] nn = NN(20, 6) # Обучаем нейронную сеть. tsample1 = [ [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 1, 0], [0, 1, 0, 1, 0, 0], [0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0], ] nn.teach(tsample1) tsample2 = [ [0, 0, 0, 0, 1, 0], [0, 0, 0, 1, 0, 0], [1, 0, 1, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], ] nn.teach(tsample2) tsample3 = [ [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0], [0, 0, 0, 1, 0, 0], [1, 0, 1, 0, 0, 0], [0, 1, 0, 0, 0, 0], ] nn.teach(tsample3) tsample4 = [ [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1], [0, 0, 1, 0, 1, 0], [0, 0, 0, 1, 0, 0], ] nn.teach(tsample4) # Проверим что может нейронная сеть. # Передадим образ чайки, который примерно похож на тот, про который знает персептрон. wsample1 = [ [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0], [1, 0, 1, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], ] print u"чайка" if nn.check(wsample1) else u"НЛО" # Передадим неизвестный образ. wsample2 = [ [0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 0], [0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], ] print u"чайка" if nn.check(wsample2) else u"НЛО" # Передадим образ чайки, который примерно похож на тот, про который знает персептрон. wsample3 = [ [0, 0, 0, 0, 1, 0], [0, 1, 0, 1, 0, 0], [0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], ] print u"чайка" if nn.check(wsample3) else u"НЛО"

Результаты

# первый запуск чайка # True НЛО # True чайка # True # второй запуск НЛО # False НЛО # True чайка # True

У приведенной реализации есть несколько слабостей, для данного примера вполне терпимых :) :

PS: Подсветка кода немного лагает, потому сорцы лучше смотреть в любимом текстовом редакторе.

Дополнительное чтиво

proft.me

Самая простая нейронная сеть на Python

Мы сейчас переживаем настоящий бум нейронных сетей. Их применяют для распознания, локализации и обработки изображений. Нейронные сети уже сейчас умеют многое что не доступно человеку. Нужно же и самим вклиниваться в это дело!

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

В качестве данных будем использовать известную в мире распознания чисел подборку данных MNIST.

Для работы с ней в Python есть библиотека python-mnist. Что-бы установить:

pip install python-mnist

Теперь можем загрузить данные

from mnist import MNIST mndata = MNIST("/path_to_mnist_data_folder/") tr_images, tr_labels = mndata.load_training() test_images, test_labels = mndata.load_testing()

Архивы с данными нужно загрузить самостоятельно, а программе указать путь к каталогу с ними.Теперь переменные tr_images и test_images содержат изображения для тренировки сети и тестирования соотвественно. А переменные tr_labels и test_labels - метки с правильной классификацией (т.е. цифры с изображений).

Все изображения имеют размер 28х28. Зададим переменную с размером.

img_shape = (28, 28)

Преобразуем все данные в массивы numpy и нормализуем их (приведем к размеру от -1 до 1). Это увеличит точность вычислений.

import numpy as np for i in range(0, len(test_images)): test_images[i] = np.array(test_images[i]) / 255 for i in range(0, len(tr_images)): tr_images[i] = np.array(tr_images[i]) / 255

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

Теперь нужно понять "что же такое нейронная сеть"!А это просто уравнение с большим количеством коэффициентов.

Мы имеем на входе массив из 28*28=784 элементов и еще по 784 веса для определения каждой цифры.В процессе работы нейронной сети нужно перемножить значения входов на веса. Сложить полученные данные и добавить смещение. Полученный результат подать на функцию активации.

В нашем случае это будет Relu. Эта функция равна нулю для всех отрицательных аргументов и аргументу для всех положительных.

Есть еще много функций активации! Но это же самая простая нейронная сеть!

Определим эту функцию при помощи numpy

def relu(x): return np.maximum(x, 0)

Теперь чтобы вычислить изображение на картинке нужно просчитать результат для 10 наборов коэффициентов.

def nn_calculate(img): resp = list(range(0, 10)) for i in range(0,10): r = w[:, i] * img r = relu(np.sum(r) + b[i]) resp[i] = r return np.argmax(resp)

Для каждого набора мы получим выходной результат. Выход с наибольшим результатом вероятнее всего и есть наше число.

В данном случае 7.

Вот и все!

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

Нужно помнить, что для того чтобы вычислить эти значения нужна производная функции активации. В нашем случае она равна нулю для всех отрицательных чисел и 1 для всех положительных.

Определим коэффициенты случайным образом.

w = (2*np.random.rand(10, 784) - 1) / 10 b = (2*np.random.rand(10) - 1) / 10 for n in range(len(tr_images)): img = tr_images[n] cls = tr_labels[n] #forward propagation resp = np.zeros(10, dtype=np.float32) for i in range(0,10): r = w[i] * img r = relu(np.sum(r) + b[i]) resp[i] = r resp_cls = np.argmax(resp) resp = np.zeros(10, dtype=np.float32) resp[resp_cls] = 1.0 #back propagation true_resp = np.zeros(10, dtype=np.float32) true_resp[cls] = 1.0 error = resp - true_resp delta = error * ((resp >= 0) * np.ones(10)) for i in range(0,10): w[i] -= np.dot(img, delta[i]) b[i] -= delta[i]

В процессе обучения коэффициенты станут слегка похожи на числа:

Проверим точность работы:

def nn_calculate(img): resp = list(range(0, 10)) for i in range(0,10): r = w[i] * img r = np.maximum(np.sum(r) + b[i], 0) #relu resp[i] = r return np.argmax(resp) total = len(test_images) valid = 0 invalid = [] for i in range(0, total): img = test_images[i] predicted = nn_calculate(img) true = test_labels[i] if predicted == true: valid = valid + 1 else: invalid.append({"image":img, "predicted":predicted, "true":true}) print("accuracy {}".format(valid/total))

У меня получилось 88%. Не так уж круто, но очень интересно!

blablacode.ru

Нейронная сеть на Python в 15 строк кода для диагностики диабета

В этой статье опишем как минимальным средствами может быть создана и обучена нейронная сеть при помощи Python и библиотеки Keras.

Нейронная сеть на Python в 15 строк кода

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

Библиотека Keras представляет собой высокоуровневый интерфейс для создания нейронных сетей. Keras написан на Python и работает поверх таких более низкоуровневых решений, как TensorFlow, CNTK и Theano. За счет этого программный код получается не только мощным, но и крайне компактным.

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

  1. Число беременностей (все пациенты из источника – женщины не моложе 21 года индийской народности пима).
  2. Концентрация глюкозы в плазме через 2 часа после введения в пероральном глюкозотолерантном тесте.
  3. Диастолическое артериальное давление (мм рт. ст.).
  4. Толщина кожной складки в районе трицепса (мм).
  5. Концентрация инсулина в сыворотке крови (мкЕд/мл).
  6. Индекс массы тела (вес в кг/(рост в м)^2).
  7. Функция, описывающая генетическую предрасположенность к диабету (diabetes pedegree).
  8. Возраст (годы).

Программный код и датасет также доступны на Github.

Библиотека Keras позволяет запускать нейронные сети с минимальным количеством операций. В качестве модели нейронной сети используется последовательная Sequental из модуля keras.models с заданием слоев keras.layers типа Dense.

from keras.models import Sequential from keras.layers import Dense import numpy

from keras.models import Sequential

from keras.layers import Dense

import numpy

Для последующей воспроизводимости результатов зафиксируем генератор случайных чисел при помощи функции random.seed() из библиотеки numpy. Считаем данные из датасета:

numpy.random.seed(2) dataset = numpy.loadtxt("prima-indians-diabetes.csv", delimiter=",")

numpy.random.seed(2)

dataset = numpy.loadtxt("prima-indians-diabetes.csv", delimiter=",")

Разделим данные на матрицу признаков X и вектор целевой переменной Y (последний столбец датасета):

X = dataset[:,0:8] Y = dataset[:,8]

X = dataset[:,0:8]

Y = dataset[:,8]

Создаем модель нейронной сети:

Опишем структуру модели нейронной сети. Определим входной, выходной и скрытые слои. Наша нейронная сеть будет иметь плотную (Dense) структуру – каждый нейрон связан со всеми нейронами следующего слоя. Выходной слой будет состоять из единственного нейрона, определяющего вероятность заболевания диабетом.

Слой добавляется к модели методом add(). Для входного слоя необходимо указать число признаков input_dim, равное в нашем случае 8:

model.add(Dense(12, input_dim=8, activation='relu'))

model.add(Dense(12, input_dim=8, activation='relu'))

Если наборы признаков образуют многомерную таблицу, то вместо параметра input_dim можно использовать параметр input_shape, принимающий кортеж с количеством элементов в каждом из измерений.

В качестве функции активации для всех слоев, кроме выходного, будем использовать функцию ReLU. Для выходного слоя воспользуемся сигмоидной функцией для определения конечной вероятности риска заболевания.

Функции активации

Создадим три скрытых слоя и один выходной слой нашей нейронной сети:

model.add(Dense(15, activation='relu')) model.add(Dense(8, activation='relu')) model.add(Dense(10, activation='relu')) model.add(Dense(1, activation='sigmoid'))

model.add(Dense(15, activation='relu'))

model.add(Dense(8, activation='relu'))

model.add(Dense(10, activation='relu'))

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

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

Перед тем, как начать тренировать модель, ее нужно скомпилировать при помощи метода compile():

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

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

Методу передается три параметра:

Для обучения нейронной сети применяем метод fit():

model.fit(X, Y, epochs = 1000, batch_size=10)

model.fit(X, Y, epochs = 1000, batch_size=10)

Параметр epochs – «эпохи» – количество проходов нейронной сети по всем записям датасета (выбирается исходя из того, насколько быстро модель с каждым новым проходом приближается к желаемой предсказательной точности), batch_size – количество объектов выборки, берущихся за один шаг. В процессе обучения API будет выводить соответствующие строчки с величинам функции потерь и метрики для каждой из эпох.

Оценим результат обучения нейронной сети. Метод evaluate() возвращает значения функции потерь и метрики для обученной модели:

scores = model.evaluate(X, Y) print("\n%s: %.2f%%" % (model.metrics_names[1], scores[1]*100))

scores = model.evaluate(X, Y)

print("\n%s: %.2f%%" % (model.metrics_names[1], scores[1]*100))

Последняя строчка в форматированном виде выводит точность прогноза по нашей модели для заданной метрики accuracy:

Наконец, полный код нейронной сети с комментариями приведен в листинге ниже:

from keras.models import Sequential from keras.layers import Dense import numpy # задаем для воспроизводимости результатов numpy.random.seed(2) # загружаем датасет, соответствующий последним пяти годам до определение диагноза dataset = numpy.loadtxt("prima-indians-diabetes.csv", delimiter=",") # разбиваем датасет на матрицу параметров (X) и вектор целевой переменной (Y) X, Y = dataset[:,0:8], dataset[:,8] # создаем модели, добавляем слои один за другим model = Sequential() model.add(Dense(12, input_dim=8, activation='relu')) # входной слой требует задать input_dim model.add(Dense(15, activation='relu')) model.add(Dense(8, activation='relu')) model.add(Dense(10, activation='relu')) model.add(Dense(1, activation='sigmoid')) # сигмоида вместо relu для определения вероятности # компилируем модель, используем градиентный спуск adam model.compile(loss="binary_crossentropy", optimizer="adam", metrics=['accuracy']) # обучаем нейронную сеть model.fit(X, Y, epochs = 1000, batch_size=10) # оцениваем результат scores = model.evaluate(X, Y) print("\n%s: %.2f%%" % (model.metrics_names[1], scores[1]*100))

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

from keras.models import Sequential

from keras.layers import Dense

import numpy

 

# задаем для воспроизводимости результатов

numpy.random.seed(2)

 

# загружаем датасет, соответствующий последним пяти годам до определение диагноза

dataset = numpy.loadtxt("prima-indians-diabetes.csv", delimiter=",")

# разбиваем датасет на матрицу параметров (X) и вектор целевой переменной (Y)

X, Y = dataset[:,0:8], dataset[:,8]

 

# создаем модели, добавляем слои один за другим

model = Sequential()

model.add(Dense(12, input_dim=8, activation='relu')) # входной слой требует задать input_dim

model.add(Dense(15, activation='relu'))

model.add(Dense(8, activation='relu'))

model.add(Dense(10, activation='relu'))

model.add(Dense(1, activation='sigmoid')) # сигмоида вместо relu для определения вероятности

 

# компилируем модель, используем градиентный спуск adam

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

 

# обучаем нейронную сеть

model.fit(X, Y, epochs = 1000, batch_size=10)

 

# оцениваем результат

scores = model.evaluate(X, Y)

print("\n%s: %.2f%%" % (model.metrics_names[1], scores[1]*100))

Источник

proglib.io


Смотрите также