Разработка автоматизированной системы классификации товаров по изображениям

 

Министерство образования и науки Российской Федерации

Федеральное государственное бюджетное образовательное учреждение

Высшего профессионального образования

"Владимирский государственный университет

имени Александра Григорьевича и Николая Григорьевича Столетовых"






ДИПЛОМНАЯ РАБОТА

Факультета прикладной математики и физики

Специальности 010501 - прикладная математика и информатика

Тема дипломной работы:

Разработка автоматизированной системы классификации товаров по их изображениям




Студента Богданова Ильи Дмитриевича

Руководитель работы: Павлова О.Н.

Допустить дипломную работу к защите в государственной

аттестационной комиссии

Заведующий кафедрой: Аракелян С.М.






г.

Аннотация


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

Ключевой частью работы является получение достаточно объёмной базы классифицированных товаров для обучения нейронных сетей. В качестве источника исходных данных взят один из крупных интернет-аукционов (molotok.ru).


Оглавление


Аннотация

Введение

1. Обзор объекта и методов исследования

1.1 Описание объекта исследования

1.2 Описание привлекаемых методов. Искусственные нейронные сети

Метод обратного распространения ошибки

Алгоритм метода обратного распространения ошибки

1.3 Среда разработки и причины ее выбора

2. Методика

2.1 Способ получения информации с веб-ресурсов

2.2 Методика классификации товаров

2.3 Алгоритм классификации товаров

2.4 Принцип хранения данных о товарах

3. Программная реализация. Апробация методики

3.1 Описание программного обеспечения

3.2 Апробация методики

Заключение

Список использованной литературы

Приложение

Введение


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

В связи с этим, при увеличении оборота товаров и их ассортимента возникает потребность в автоматизированной системе классификации товаров.

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

В качестве объекта исследования рассматривается интернет-аукцион molotok.ru.

классификация товар алгоритм программный

1. Обзор объекта и методов исследования


1.1 Описание объекта исследования


Молоток. ру - один из крупнейших интернет аукционов в России. На сайте представлено порядка 5 000 000 уникальных лотов, все они хорошо структурированы и находятся более чем в 5000 категорий.

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

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


1.2 Описание привлекаемых методов. Искусственные нейронные сети


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


Схема трехслойной нейронной сети


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

Персептрон - математическая и компьютерная модель восприятия информации мозгом (кибернетическая модель мозга), предложенная Фрэнком Розенблаттом.

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

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


Метод обратного распространения ошибки

Метод обратного распространения ошибки - метод обучения многослойного персептрона, один из вариантов обучения с учителем. Впервые метод был описан Полом Дж. Вербосом. Далее существенно развит в 1986 г. Дэвидом И. Румельхартом, Дж.Е. Хинтоном и Рональдом Дж. Вильямсом. Это итеративный градиентный алгоритм, который используется с целью минимизации ошибки работы многослойного перцептрона и получения желаемого выхода.

Основная идея этого метода состоит в распространении сигналов ошибки от выходов сети к её входам, в направлении, обратном прямому распространению сигналов в обычном режиме работы. Барцев и Охонин предложили сразу общий метод ("принцип двойственности"), приложимый к более широкому классу систем, включая системы с запаздыванием, распределённые системы, и т.п.

Метод является модификацией классического метода градиентного спуска.


Алгоритм метода обратного распространения ошибки

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

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


, (1)


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

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


, (2)


где весовой коэффициент j-го нейрона n-го слоя для связи с i-м нейроном (n-1) - го слоя. Параметр называется параметром скорости обучения.

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


(3)


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


. (4)


Третий сомножитель / есть ни что иное, как выход i-го нейрона (n-1) - го слоя, то есть


. (5)


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

Производя дифференцирование (1) по и учитывая (3) и (5) будем иметь


(6)


Введем обозначение


. (7)


Тогда для нейронов выходного слоя


. (8)


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


(9)


Заметим, что в этой формуле первые два сомножителя есть не что иное, как . Таким образом, с помощью (9) можно выражать величины для нейронов n-го слоя через для нейронов (n+1) - го. Поскольку для последнего слоя легко вычисляется по (8), то можно с помощью рекурсивной формулы


(10)


получить значения для вех нейронов всех слоев.

Окончательно формулу (2) для модификации весовых коэффициентов можно записать в виде


. (11)


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

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

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

Рассчитать по формуле (8) . Затем с помощью рекурсивной формулы (10) подсчитываются все остальные и, наконец, с помощью (11) изменение весовых коэффициентов сети.

Скорректировать веса сети:


.


Рассчитать целевую функцию (1). Если она достаточно мала, считаем сеть успешно обучившейся. Иначе возвращаемся на шаг 2.


Оценка работы сети

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


, (17)


где - требуемое значение выходного сигнала.

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

Недостатки алгоритма

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

Паралич сети

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

Локальные минимумы

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

Размер шага

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

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


1.3 Среда разработки и причины ее выбора


Разработка приложения будет осуществляться на языке программирования C# с фреймворком.net Framework 4.0 в среде разработки Microsoft Visual Studio 2010. Фрагменты кода, требующие массивных вычислений, разработаны на языке C++. MS Visual Studio 2010 включает в себя полный набор новых и улучшенных функций, упрощающих все этапы процесса разработки от проектирования до развертывания.Visual Studio 2010 Ultimate - интегрированная среда инструментальных средств и серверная инфраструктура, упрощающая процесс разработки приложения в целом. Для создания бизнес-приложений используются эффективные, предсказуемые, настраиваемые процессы. Детальная аналитика повышает прозрачность и прослеживаемость всего жизненного цикла приложения. Как при создании новых решений, так и при доработке существующих, доступна разработка с помощью мощных инструментов создания прототипов, проектирования архитектуры и разработки, которые позволяют разрабатывать приложения для всевозможных платформ и технологий, таких как обработка данных в облаке и параллельная обработка данных. Расширенные возможности координирования совместной деятельности наряду с интегрированными инновационными инструментами тестирования и отладки обеспечат повышение производительности группы и создание высококачественных и недорогих решений.

Разработка приложений в Microsoft Visual Studio 2010 Ultimate на языке C# с фреймворком.net Framework 4.0 осуществляется с применением объектно-ориентированного программирования и визуального программирования.


2. Методика


2.1 Способ получения информации с веб-ресурсов


При исследовании средств получения информации с сайта molotok.ru выявлено отсутствие API, позволяющего получить необходимые исходные данные. Поэтому получение информации будет производиться непосредственно с веб-страниц сайта. Для этого необходим программный доступ к элементам страницы. Также необходимо учесть, что часть элементов на странице генерируются при помощи JavaScript и AJAX. Поэтому выполнения простых HTTP запросов (классы WebRequest и WebResponse) недостаточно, необходимо обеспечить выполнение JavaScript и AJAX на странице. В связи с этим в качестве объекта, получающего страницы с сайта, был выбран стандартный для MS Visual Studio класс WebBrowser, который представляет оболочку для неуправляемого объекта на основе браузера Internet Explorer, версии идентичной установленному в системе.

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

Сайт molotok.ru является крупным интернет-аукционом с большим количеством категорий, в которых может представляться товар. Таким образом, сначала необходимо получить полный список категорий, с сохранением уровней вложенности т.к. это потребуется в дальнейшем. Это удобно сделать при помощи веб-страницы сайта "Карта категорий" (#"470" src="doc_zip35.jpg" />

Алгоритм получения категорий с веб-ресурса


Следующий этап состоит в получении ссылок на изображения товаров. Для этого необходимо посетить страницы каждой категории, учитывая, что в категории может быть несколько страниц с товарами, но одновременно на странице отображается не более 25 товаров. Открывать страницы с самими товарами не обязательно, так как вся необходимая информация о товарах содержится в html-элементе <table>, который содержит в себе товары и всю информацию о каждом из них. Информацию о товаре можно разделить на два типа: текстовая (Идентификатор товара) и графическая (Изображения товара). Интернет-аукцион сохраняет все изображения товаров на внутреннем хостинге изображений, где они проходят предварительную обработку и приводятся к двум форматам: 64x48 и 400x300. Для каждого товара извлекаются и сохраняются в БД ссылки на его изображения. Следует отметить, что ссылки разделаются на два типа, согласно двум форматам изображений. Этот этап происходит в многопоточном режиме для уменьшения времени, требуемого для обработки товаров. На рисунке далее приведена схема алгоритма.


Схема алгоритма получения информации о товарах


На последнем этапе программа считывает из БД ссылки на изображения, загружает изображения и сохраняет их на диск, структурируя их при помощи каталогов. Структура имеет следующий вид: каталог размера изображения, каталог категории изображения, каталог товара изображения. Так же есть возможность не обращаться к БД для ускорения работы, если ссылки уже были инициализированы в памяти на предыдущем этапе. Для загрузки изображений по ссылкам используются классы WebRequest и WebResponse. Загрузка происходит в многопоточном режиме.


2.2 Методика классификации товаров


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

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

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


2.3 Алгоритм классификации товаров


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

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

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

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


Схема алгоритма классификации товаров


2.4 Принцип хранения данных о товарах


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

Для хранения дерева категорий, ссылок на изображения товаров и настроек программы используется реляционная база данных. В качестве СУБД используется MS SQL Server 2008 R2 Express SP1.

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

На рисунке ниже приведена структура базы данных.


Структура базы данных


Приведем описание таблиц, полей и типов данных, использованных в базе данных:

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

setting - хранит название настройки, тип данных varchar.

value - хранит значение настройки, тип данных varchar.

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

itemId - хранит идентификатор изображения, полученных с веб-ресурса, тип данных bigint.

categoryId - хранит идентификатор категории, к которой относится изображение, тип данных int.

URL - хранит ссылку на изображение, тип данных varchar.

isBig - флаг, определяющий, имеет ли изображение большое разрешение, тип данных bit.

Таблица Categories хранит данные о категориях и их структуре. Приведем описание полей:

id - хранит идентификатор категории, полученный с веб-ресурса, тип данных int.

[level] - уровень категории, тип данных int.

name - название категории, тип данных varchar.

url - ссылка на категорию, тип данных varchar.

parentUrl - ссылка на родительскую категорию, тип данных varchar.

3. Программная реализация. Апробация методики


3.1 Описание программного обеспечения


Для обработки данных разработана программа на языке программирования C# на платформе.net 4.0 в среде программирования Microsoft Visual Studio 2010 Ultimate Edition. Хранение данных осуществлено с использованием СУБД MS SQL Server 2008 R2 Express Edition SP1.

Программа, извлекающая данные с веб-ресурса обрабатывает информацию следующего вида:

1.Страница, с данными о товарах.

2.Идентификатор товара.

.Ссылка на товар

.Категория товара

.Изображения товара.

Результатами работы приложения является:

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

Структурированные, сохранённые локально изображения товаров.

Программа, классифицирующая товары обрабатывает информацию следующего вида:

1.Изображения товаров

2.Информация для обучения сетей

.Конфигурации сетей

Результатами работы приложения является:

Ответ программы о принадлежности товара к категории.

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

На рисунке 6 представлена структурная схема приложения:


Структурная схема приложения


На рисунке 7 представлена структура работы приложения, извлекающего данные с веб-ресурса:


Структура работы приложения извлекающего данные с веб-ресурса


На рисунке 8 представлена структура работы приложения, классифицирующего товары:


Структура работы приложения классифицирующего товары


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

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

DBEngine - модуль для осуществления работы с БД.

ThreadHelper - модуль, содержащий функции для распределения общего объёма работы между потоками.

Logger - модуль, осуществляющий работу с лог-файлами.

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

NeuralNetwork - модуль, содержащий функции для работы с единичной нейронной сетью.

TrainData - модуль формирования информации для обучения нейронных сетей.

NetworkController - модуль для управления работой массива нейронных сетей.

NetworkPool - модуль для группировки нейронных сетей и определения результата классификации.

Описание классов.

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

Класс Category описывает категорию товаров.

Приведём структуру класса:

public class Category

{int id; // ИД категории в системе сайтаint level; // Уровень вложенияstring name; // Названиеstring url; // ссылкаstring parentURL; // ссылка на категорию-родительList<Image> categoryImages; // изображения товаров

}

Класс Image описывает изображение товара.

Приведём структуру класса:

public class Image

{Int64 itemId; // ИД товараint categoryId; // ИД категорииstring URL; // ссылка на изображенияbool isBig; // флаг, показывающий, имеет ли изображение большое разрешение

}

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

Класс DBEngine является контроллером при работе с базой данных.

Приведём структуру класса:

public class DBEngine

{connectionString; // строка подключенияCategoryTable categoryTable; // таблица категорийImageTable imageTable; // таблица изображенийSettingsTable settingsTable; // таблица настроек

}

Класс EngineTable является классом-родителем классам для работы с таблицами базы данных.

Приведём структуру класса:

public class EngineTable

{string tableName; // Имя таблицыstring connectionString; // строка подключения

}

Класс CategoryTable используется для работы с таблицей категорий в базе данных, является наследником класса EngineTable.

Класс ImageTable используется для работы с таблицей изображений в базе данных, является наследником класса EngineTable.

Класс SettingsTable используется для работы с таблицей настроек в базе данных, является наследником класса EngineTable.

Класс BrowserExtensions используется для расширения возможностей встроенного класса WebBrowser.

Класс TreeViewExtension используется для расширения возможностей встроенного класса TreeView.

Класс Grabber служит для извлечения информации с веб-ресурса.

Приведём структуру класса:

class Grabber

{. DBEngine dbEngine; // движок БД<Category> categories; // категорииgetItemCounter; // счетчик получения товаровgetItemWorkAmount; // обьём работы получения товаровgetItemThreadCount; // количество потоков получения товаровint GetItemThreadCount

{{ return getItemThreadCount; }{ getItemThreadCount = value; }

}saveImageCounter; // счетчик сохранения изображенийsaveItemWorkAmount; // объём работы сохранения изображенийsaveItemThreadCount; // количество потоков сохранения изображенийint SaveItemThreadCount

{{ return saveItemThreadCount; }{ saveItemThreadCount = value; }

}

}

Класс NeuralNetwork управляет единичной нейронной сетью.

Приведём структуру класса:

partial class NeuralNetwork

{net; // нейронная сеть[] neuronsInLayers; // количество нейронов в слояхint id; // ИДCategory levelTwoParent; // категория родитель уровня 2Category category; // категорияstring Name // имя

{{ return category. name; }

}int Level // уровень

{{ return category. level; }

}

}

Класс NetworkPool используется для группировки сетей и определения результата классификации, не содержит полей.

Класс NetworkController управляет массивом нейронных сетей.

Приведём структуру класса:

class NetworkController

{dbEngine; // движок БД<NeuralNetwork> smallNetworks; // маленькие сети<NeuralNetwork> bigNetworks; // большие сетиDictionary<NeuralNetwork, double [] > workResult; // результат работы сетейsmallNetworksInitialized; // флаг инициализации малых сетейbool SmallNetworksInitialized

{{ return smallNetworksInitialized; }

}bigNetworksInitialized; // флаг инициализации больших сетейbool BigNetworksInitialized

{{ return bigNetworksInitialized; }{ bigNetworksInitialized = value; }

}initialDirectory; // рабочая директорияstring InitialDirectory

{{ return initialDirectory; }

}[] smallNetworkLayers = { 3072, 512, 1 }; // слои малых сетей[] bigNetworkLayers = { 12000, 1000, 1 }; // слои больших сетейtrainDataCreationCounter; // счетчик создания данных для обученияtrainDataCreationWorkAmount; // объём работы данных обученияtrainDataCreationThreadCount; // количество потоков данных обученияint TrainDataCreationThreadCount

{{ return trainDataCreationThreadCount; }{ trainDataCreationThreadCount = value; }

}networkTrainCounter; // счетчик обучения сетейnetworkTrainWorkAmount; // объём работы обучения сетейnetworkTrainThreadCount; // количество потоков обучения сетейint NetworkTrainThreadCount

{{ return networkTrainThreadCount; }{ networkTrainThreadCount = value; }

}networkCreateCounter; // счетчик создания сетейnetworkCreateWorkAmount; // объём создания сетейnetworkCreateThreadCount; // потоки создания сетейint NetworkCreateThreadCount

{{ return networkCreateThreadCount; }{ networkCreateThreadCount = value; }

}

}


Описание интерфейса работы программы

При запуске программы появляется главное окно приложения:


Окно программы после запуска


Приведем описание интерфейса.

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

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


Окно программы с загруженным списком категорий


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

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


Процесс парсинга указанных категорий


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



Работа окончена


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

Главное окно программы для классификации товаров


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

При нажатии кнопки подготовить данные для обучения программа начнет работу:


Создание файлов обучения


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

Для классификации товара, нужно нажать кнопку "Работать", затем выбрать изображение этого товара, и дождаться результата классификации.


Результат классификации


3.2 Апробация методики


Для тестирования методики классификации товаров была произведена случайная выборка 20 категорий, общее количество товаров составило 8442, образов - 19863. Классификация осуществлялась в восемь потоков. Для осуществления тестирования были отобраны 2000 случайных товаров, по 100 штук для каждой категории, успешным результат тестирования для одного товара считался, если сеть, к категории которой принадлежит данный товар, возвращала выходной сигнал на 90% и более соответствующий эталонному сигналу. Настройки нейронных сетей: число нейронов во входном слое - 3072, в скрытом - 512, в выходном - 1, шаг обучения 1*10-10, максимальное количество эпох при обучении - 1*109, максимально допустимая погрешность - 1*10-10.


Процент верно классифицированных товаров по категориям


Как видно из графика, представленного на рисунке выше, точность классификации товаров варьируется от 66 до 89%. Точность классификации напрямую зависит от количества образов, которое было дано сети для обучения. Максимальная точность была достигнута для сети с 4867 образами. Соответствие категорий их идентификаторам приведено в таблице 1.


Таблица 1

Наименование категорииИдентификаторНожи65655Фонари68548Цифровые зеркальные камеры70303Роликовые коньки72009Дефлекторы72010Палатки72011Фаркопы72012Гири72013Гантели72014Мячи72015Материнские платы75149Шахматы105062iPhone105353iPhone 3GS105354iPhone 3GS White105355iPhone 4S105356iPhone 4S White105357USB флешки106445Металлоискатели108909

Нейронные сети в основе системы были выбраны потому, что немаловажным аспектом работы программы является её быстродействие, далее будет осуществлено тестирование скорости работы приложения.

Тестовая конфигурация аппаратного обеспечения приведена в таблице 2.


Таблица 2

Процессор AMD FX-8120 4600 MHzОперативная памятьKingston HyperX T1 16Gb 1866 MHzЖесткий дискOCZ Vertex Turbo 30Gb, 2xWD Caviar Green 1Tb Raid1Блок питанияEnermax Revolution85+ 920W

Результаты тестирования производительности будут представлены в порядке последовательного выполнения всех узлов программы: от парса категорий до непосредственной работы нейронных сетей. Всего на сайте представлено 5116 категорий, общее время парса всех категорий составляет 36-38 секунд.


Время парсинга категорий


На графике, изображенном на рисунке 17, представлены произвольные 11 категорий, максимальное время парса составляет 0,0204 сек, минимальное - 0,0058 сек, среднее - 0,0122 сек.

Теперь будет приведён тест производительности при парсинге товаров. Товары на сайте представлены страницами по 25 товаров на каждой странице. Максимальное время парса страницы - 2,8057 сек, минимальное - 1,6170 сек, среднее - 2,1116 сек.


Время парсинга товаров


На рисунке 18 изображен график, на котором представлены 50 случайных товаров и время их парсинга. Минимальное время составляет 0,0003 сек, максимальное - 0,0023 сек, среднее время - 0,0007 сек.


Время сохранения изображений на диск


На данном графике (рис. 19) представлен результат тестирования производительности сохранения 250 случайных изображений на диск. Минимальное время равно 0,0662 сек, максимальное составляет 0,3213 сек, среднее - 0,0996 сек.

Ранее упоминалось, что общее число изображений для тестирования составляет 19863. Приведём тестирование производительности на этапе подготовки образов для дальнейшего обучения нейронных сетей. Образы обрабатывались для подготовки различным нейронным сетям. Максимальное время обработки - 0,03217 сек, минимальное - 0,01103 сек, среднее - 0,02054. График, наглядно отображающий время, затраченное на обработку каждого набора изображений, представлен на рисунке 20.


Время подготовки данных для обучения нейронных сетей


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


Время обучения нейронных сетей


На рисунке 21 представлен график, на котором отображено время обучения нейронных сетей. Максимальное время составляет 0, 2057 сек, минимальное - 0,1054 сек, среднее - 0,0932 сек.

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


Время сохранения файлов конфигурации нейронных сетей на диск


Как видно из графиков, представленных на рисунке 22, максимальное время сохранения конфигурационного файла сети составляет 5,68 сек, минимальное - 5,52 сек, среднее - 5,60 сек.

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


Время инициализации нейронных сетей


Из графиков, представленных на рисунке 23, видно, что максимальное время инициализации нейронной сети равно 6,12 сек, минимальное - 5,95 сек, среднее - 6,00 сек.

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


Время работы нейронных сетей


Изучив графики с рисунка 24 можно сделать вывод, что максимальное время работы одиночной нейронной сети составляет 0,01046 сек, минимальное - 0,00860 сек, среднее - 0,00915 сек.

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

Заключение


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

Также был проведен анализ объекта исследования и привлекаемых для решения поставленной задачи методов.

Алгоритм классификации товаров по их изображениям был реализован на языке C#. Работоспособность данного алгоритма проверялась с помощью данного программного продукта.

Апробация методики проводилась на фактических данных из нескольких случайных категорий веб-ресурса molotok.ru.

Разработанная система классификации товаров была внедрена и используется для осуществления коммерческой деятельности на предприятии ООО "Алсени".

Список использованной литературы


1.Абрамян М. Visual C# на примерах. - Санкт Петербург: BHV-Санкт-Петербург, 2008 - 496с.

2.Евсеева О.Н., Шамшев А.Б. Работа с базами данных на языке C#. Технология ADO.net. - Ульяновск: УлГТУ, 2009 - 176с.

.Комарцова Л.Г., Максимов А.В. Нейрокомпьютеры. - М.: МГТУ им. Н.Э. Баумана, 2004. - 400с.

.Круглов В.В., Борисов В.В. Искусственные нейронные сети. Теория и практика. - М.: Горячая линия - Телеком, 2001. - 382с.

5.Хабрахабр [Электронный ресурс]: Распараллеливание задач. Случай "идеальной параллельности". Часть 1. Режим доступа: <#"center">Приложение


Листинг программы

Модуль Threading

using System;System. Collections. Generic;System. Linq;System. Text;grabberMolotok. Threading

{class ThreadHelper

{static List<Type> [] SplitList<Type> (List<Type> list, int splits)

{count = list. Count;(count < splits)

{<Type> [] resultList = new List<Type> [count];(int i = 0; i < count; i++)

{[i] = new List<Type> ();[i]. Add (list [i]);

}resultList;

}<Type> [] splittedList = new List<Type> [splits];splitSize = count / splits;lastSplit = count % splits;(int i = 0; i < splits - 1; i++)

{[i] = new List<Type> ();(int j = 0; j < splitSize; j++)

{[i]. Add (list [i * splitSize + j]);

}

}[splits - 1] = new List<Type> ();(int j = 0; j < splitSize + lastSplit; j++)

{[splits - 1]. Add (list [splits - 1 * splitSize + j]);

}splittedList;

}static int CountWorkAmount<Type> (List<Type> [] list)

{counter = 0;(var l in list)(var el in l)++;counter;

}

}

}

Модуль DBWorker

using System;System. Collections. Generic;System. Linq;System. Text;System. Data;System. Data. SqlClient;grabberMolotok. DBEngine

{class DBEngine

{connectionString; // строка подключенияCategoryTable categoryTable; // таблица категорийImageTable imageTable; // таблица изображенийSettingsTable settingsTable; // таблица настроекDBEngine ()

{builder = new SqlConnectionStringBuilder ();. DataSource =". \\SQLExpress";. InitialCatalog = "molotokdb";. IntegratedSecurity = true;= builder. ToString ();();

}InitTables ()

{= new CategoryTable (connectionString);= new ImageTable (connectionString);= new SettingsTable (connectionString);

}void ClearTables ()

{. Clear ();. Clear ();

}

}

}System;System. Collections. Generic;System. Linq;System. Text;System. Data;System. Data. SqlClient;grabberMolotok. DBEngine

{class CategoryTable: EngineTable

{CategoryTable (string connectionString)

{. tableName = "Categories";. connectionString = connectionString;

}void Insert (List<Category> categories)

{(this)

{connection = new SqlConnection (connectionString);insertCategoryCommand = new SqlCommand ("sp_InsertCategory", connection);.commandType = CommandType. StoredProcedure;. UpdatedRowSource = UpdateRowSource. OutputParameters;(insertCategoryCommand. Parameters);. Open ();(var category in categories)

{(insertCategoryCommand. Parameters, category);. ExecuteNonQuery ();

}. Close ();

}

}void Insert (Category c)

{(this)

{connection = new SqlConnection (connectionString);insertCategoryCommand = new SqlCommand ("sp_InsertCategory", connection);.commandType = CommandType. StoredProcedure;. UpdatedRowSource = UpdateRowSource. OutputParameters;(insertCategoryCommand. Parameters);. Open ();(insertCategoryCommand. Parameters, c);. ExecuteNonQuery ();. Close ();

}

}List<Category> GetAll ()

{(this)

{connection = new SqlConnection (connectionString);<Category> categoryList = new List<Category> ();getCommand = new SqlCommand ("SELECT * FROM " + tableName, connection);. Open ();reader = getCommand. ExecuteReader ();(reader. Read ())

{. Add (GetFromReader (reader));

}. Close ();categoryList;

}

}Category GetById (int id)

{(this)

{c = null;connection = new SqlConnection (connectionString);<Category> categoryList = new List<Category> ();getCommand = new SqlCommand ("SELECT * FROM " + tableName + " WHERE id=@id", connection);. Parameters. Add (new SqlParameter ("@id", id));. Open ();reader = getCommand. ExecuteReader ();(reader. Read ())= GetFromReader (reader);. Close ();c;

}

}

#region Мелкие функцииCategory GetFromReader (SqlDataReader reader)

{c = new Category ();. id = (int) reader ["id"];. level = (int) reader ["level"];. name = (string) reader ["name"];. url = (string) reader ["url"];. parentURL = (string) reader ["parentUrl"];c;

}void GetCommandParameters (SqlParameterCollection parameters)

{. Clear ();. Add ("@id", SqlDbType. Int);. Add ("@level", SqlDbType. Int);. Add ("@name", SqlDbType. VarChar);. Add ("@url", SqlDbType. VarChar);. Add ("@parentUrl", SqlDbType. VarChar);

}void FillCommandParameters (SqlParameterCollection parameters, Category c)

{["@id"]. Value = c. id;["@level"]. Value = c. level;["@name"]. Value = c. name;["@url"]. Value = c. url;["@parentUrl"]. Value = c. parentURL;

}

#endregion

}

}

Модуль Grabber

using System;System. Collections. Generic;System. Linq;System. Text;System.net;System. IO;System. Windows. Forms;System. Text. RegularExpressions;System. Threading;System. Diagnostics;grabberMolotok. Threading;grabberMolotok

{Grabber

{. DBEngine dbEngine; // движок БД<Category> categories; // категорииgetItemCounter; // счетчик получения товаровgetItemWorkAmount; // объём работы получения товаровgetItemThreadCount; // количество потоков получения товаровint GetItemThreadCount

{{ return getItemThreadCount; }{ getItemThreadCount = value; }

}saveImageCounter; // счетчик сохранения изображенийsaveItemWorkAmount; // объём работы сохранения изображенийsaveItemThreadCount; // количество потоков сохранения изображенийint SaveItemThreadCount

{{ return saveItemThreadCount; }{ saveItemThreadCount = value; }

}

#region Событияdelegate void AllCategoriesParseCompletedEventHandler ();static event AllCategoriesParseCompletedEventHandler AllCategoriesParseCompletedEvent;delegate void AllCategoriesImageSaveCompletedEventHandler ();static event AllCategoriesImageSaveCompletedEventHandler AllCategoriesImageSaveCompletedEvent;delegate void CategoriesGotEventHandler ();static event CategoriesGotEventHandler CategoriesGotEvent;OnCategoryParseComplete ()

{++;(getItemCounter == getItemWorkAmount)

{();

}

}OnCategoryImageSaveComplete ()

{++;(saveImageCounter == saveItemWorkAmount)

{(AllCategoriesImageSaveCompletedEvent! = null)();

}

}

#endregion СобытияGrabber ()

{. CategoryParseCompletedEvent += new Category. CategoryParseCompletedEventHandler (this. OnCategoryParseComplete);. CategoryImageSaveCompletedEvent += new Category. CategoryImageSaveCompletedEventHandler (this. OnCategoryImageSaveComplete);= new DBEngine. DBEngine ();= new List<Category> ();= 0;= - 1;= 8;= 0;= - 1;= 8;

}

// / <summary>

// / Получает список категорий с молотка

// / </summary>void GetCategories ()

{. WriteLine ("Получение категорий с сайта");wB = new WebBrowser ();. ScriptErrorsSuppressed = true;url = "#"justify">. GetInnerElements ("table", 0)

. GetInnerElements ("tbody", 0)

. GetInnerElements ("tr",

)

. GetInnerElements ("td", 1)

. GetInnerElements ("div");(var columnDiv in columnDivList)

{. AddRange (columnDiv. GetInnerElements ("div"));

}. WriteLine ("Категории получены с сайта");(categoriesHtmlList);(CategoriesGotEvent! = null)();

}

// / <summary>

// / Парсит полученные с молотка категории

// / </summary>

// / <param name="categoriesHtmlList"></param>ParseCategories (List<HtmlElement> categoriesHtmlList)

{. WriteLine ("Начался парс категорий");[] LastLevelURL = new string [4];catName;catURL;catClass;catLevel;catSiteId;wholeStopwatch = Stopwatch. StartNew ();(var categoryHtml in categoriesHtmlList)

{

// Stopwatch stopwatch = Stopwatch. StartNew ();= GetName (categoryHtml);= GetURL (categoryHtml);= GetClass (categoryHtml);= GetLevel (catClass);= GetSiteID (categoryHtml);c = null;(catLevel)

{0:

{= new Category (catURL, "this is root", catName, 0, catLevel);[0] = catURL;. Add (c);;

}1:

{= new Category (catURL, LastLevelURL [0], catName, catSiteId, catLevel);[1] = catURL;. Add (c);;

}2:

{= new Category (catURL, LastLevelURL [1], catName, catSiteId, catLevel);[2] = catURL;. Add (c);;

}3:

{= new Category (catURL, LastLevelURL [2], catName, catSiteId, catLevel);[3] = catURL;. Add (c);;

}4:

{= new Category (catURL, LastLevelURL [3], catName, catSiteId, catLevel);. Add (c);;

}: { break; }

}

// stopwatch. Stop ();

// Debug. WriteLine ( ( (double) stopwatch. ElapsedTicks / (double) Stopwatch. Frequency). ToString ());

}. Stop ();. WriteLine ("Время парса всех категорий " + ( (double) wholeStopwatch. ElapsedTicks / (double) Stopwatch. Frequency). ToString () + "с");. WriteLine ("Парс категорий окончен");

}

#region Методы DBEnginevoid ClearTables ()

{. ClearTables ();

}void ClearCategories ()

{. categoryTable. Clear ();

}string ReadSetting (string settingName)

{dbEngine. settingsTable. ReadSetting (settingName);

}

// / <summary>

// / Сохраняет ссылки на изображения в БД

// / </summary>

// / <param name="c"></param>void SaveImages (Category c)

{. imageTable. Insert (c. categoryImages);

}

// / <summary>

// / Загружает ссылки на изображения из БД

// / </summary>

// / <param name="c"></param>void LoadImages (Category c)

{. categoryImages = dbEngine. imageTable. GetImagesInCategory (c);

}

// / <summary>

// / Сохраняет категории в БД

// / </summary>void SaveCategories ()

{. categoryTable. Insert (categories);

}Category GetCategoryById (int id)

{dbEngine. categoryTable. GetById (id);

}

// / <summary>

// / Загружает категории из БД

// / </summary>void LoadCategories ()

{= dbEngine. categoryTable. GetAll ();(CategoriesGotEvent! = null)();

}

#endregion

#region Работа со списком категорий

// / <summary>

// / Возвращает список дочерних категорий (рекурсивная)

// / </summary>

// / <param name="root">Начальная категория</param>

// / <returns></returns>List<Category> GetAllChildCategories (Category root)

{<Category> childs = new List<Category> ();. AddRange (. FindAll ((Category category)

{category. parentURL == root. url;

}

)

);count = childs. Count;(count > 0 && root. level < 4)

{(int i = 0; i < count; i++)

{. AddRange (GetAllChildCategories (childs [i]));

}

}childs;

}

// / <summary>

// / Возвращает список дочерних категорий

// / </summary>

// / <param name="root"></param>

// / <returns></returns>List<Category> GetChildCategories (Category root)

{<Category> childs = new List<Category> ();. AddRange (. FindAll ((Category category)

{category. parentURL == root. url;

}

)

);childs;

}

// / <summary>

// / Возвращает категории уровня 0

// / </summary>

// / <returns></returns>List<Category> GetRoots ()

{<Category> roots = new List<Category> ();. AddRange (. FindAll ((Category category)

{category. level == 0;

}

)

);roots;

}

#endregion

#region Вспомогательные функцииGetName (HtmlElement e)

{(e. FirstChild! = null && e. FirstChild. FirstChild! = null) return e. FirstChild. FirstChild. InnerText;"";

}GetURL (HtmlElement e)

{(e. FirstChild! = null) return e. FirstChild. GetAttribute ("href"). Replace ("about:", "#"justify">}GetClass (HtmlElement e)

{classExpression = new Regex (@"class=. {1} ([\w\d\s] *)", RegexOptions. IgnoreCase | RegexOptions.compiled);match = classExpression. Match (e. OuterHtml);(match. Success)

{match. Groups [1]. Value;

}"";

}GetLevel (string classLevel)

{classExpression = new Regex (@" (\d{1})", RegexOptions. IgnoreCase | RegexOptions.compiled);match = classExpression. Match (classLevel);(match. Success)

{Convert. ToInt32 (match. Groups [1]. Value);

}- 1;

}GetSiteID (HtmlElement e)

{siteIdExpression = new Regex (@" (\d{5,})", RegexOptions. IgnoreCase | RegexOptions.compiled);match = siteIdExpression. Match (e. OuterHtml);(match. Success)

{Convert. ToInt32 (match. Groups [1]. Value);

}- 1;

}

#endregion

// / <summary>

// / Получает изображения в категории, в несколько потоков

// / </summary>

// / <param name="cats"></param>void ParallelGetItems (List<Category> cats)

{. WriteLine ("Запуск потоков парса ссылок на изображения");. getItemCounter = 0;. getItemWorkAmount = cats. Count;preparedList = ThreadHelper. SplitList (cats, getItemThreadCount);(var categories in preparedList)

{thread = new Thread (()

{(var cat in categories)

{. GetItems ();. Sleep (10);

}

}

);. SetApartmentState (ApartmentState. STA);. Start ();. Join (10);

}

}void ParallelSaveImagesToDisk (List<Category> cats)

{. WriteLine ("Запуск потоков закачки изображений");. saveImageCounter = 0;. saveItemWorkAmount = cats. Count;initialDirectory = ReadSetting ("initialDirectory");preparedList = ThreadHelper. SplitList (cats, saveItemThreadCount);(var categories in preparedList)

{thread = new Thread (()

{(var cat in categories)

{. SaveImages (initialDirectory);. Sleep (10);

}

}

);. SetApartmentState (ApartmentState. STA);. Start ();. Join (10);

}

}

}

}System;System. Collections. Generic;System. Linq;System. Text;System.net;System. IO;System. Text. RegularExpressions;System. Windows. Forms;System. Threading;System. Diagnostics;grabberMolotok

{class Category

{int id; // ИД категории в системе сайтаint level; // Уровень вложенияstring name; // Названиеstring url; // ссылкаstring parentURL; // ссылка на категорию-родительList<Image> categoryImages; // изображения товаров

#region Событияdelegate void CategoryParseCompletedEventHandler ();static event CategoryParseCompletedEventHandler CategoryParseCompletedEvent;delegate void CategoryImageSaveCompletedEventHandler ();static event CategoryImageSaveCompletedEventHandler CategoryImageSaveCompletedEvent;

#endregion

#region КонструкторыCategory (string url, string parentURL, string name, int id, int level)

{. url = url;. parentURL = parentURL;. name = name;. id = id;. level = level;= new List<Image> ();

}Category (string url)

{. id = - 1;. level = - 1;. name = null;. url = url;. parentURL = null;= new List<Image> ();

}Category ()

{. id = - 1;. level = - 1;. name = null;. url = null;. parentURL = null;= new List<Image> ();

}

#endregion

// / <summary>

// / Получает список товаров в категории

// / </summary>void GetItems ()

{wB = new WebBrowser ();. ScriptErrorsSuppressed = true;pageCount = 0;<HtmlElement> htmlItems = new List<HtmlElement> ();url = this. url;. NavigateFromRequest (url);

{htmlPageCount = wB. WaitElement ("tabMainBox", 20000)

. GetInnerElements ("div", 0)

. GetInnerElements ("div", 0)

. GetInnerElements ("div", 0)

. GetInnerElements ("span", 1);pageCountRegex = new Regex (@"< [\D] span> (\d*) < [\D] span>", RegexOptions. IgnoreCase | RegexOptions.compiled);match = pageCountRegex. Match (htmlPageCount. OuterHtml);(match. Success)

{= Convert. ToInt32 (match. Groups [1]. Value);

}

}(NullReferenceException)

{= 1;

}(int i = 1; i <= pageCount; i++)

{(int tries = 0; tries < 5; tries++)

{

{

// Stopwatch watch = Stopwatch. StartNew ();. NavigateFromRequest ("#"justify">. GetInnerElements ("div", 1)

. GetInnerElements ("table", 0)

. GetInnerElements ("tbody", 0)

. GetInnerElements ("tr")

);

// watch. Stop ();

// Debug. WriteLine ( ( (double) watch. ElapsedTicks / (double) Stopwatch. Frequency). ToString ());;

}(NullReferenceException)

{. Sleep (50);

}

}

}(htmlItems);();

}

// / <summary>

// / Парсит товары в категории

// / </summary>

// / <param name="itemsHtmlList"></param>

// / <param name="cat"></param>ParseItems (List<HtmlElement> itemsHtmlList)

{. WriteLine ("Начался парс товаров");itemIdRegex = new Regex ("data-id= ([\\d] *)", RegexOptions. IgnoreCase | RegexOptions.compiled);smallPicturesRegex = new Regex (@" (#"justify">{

// Stopwatch watch = Stopwatch. StartNew ();

/************************************/itemId = - 1;<Image> imgList = new List<Image> ();;matchId = itemIdRegex. Match (item. OuterHtml);(matchId. Success)

{= Convert. ToInt64 (matchId. Groups [1]. Value);

}matchsmallPictures = smallPicturesRegex. Match (item. OuterHtml);(matchsmallPictures. Success)

{. AddImage (itemId, matchsmallPictures. Groups [1]. Value, false);= matchsmallPictures. NextMatch ();

}matchbigPictures = bigPicturesRegex. Match (item. OuterHtml);(matchbigPictures. Success)

{. AddImage (itemId, matchbigPictures. Groups [1]. Value, true);= matchbigPictures. NextMatch ();

}

/********************************************/

// watch. Stop ();

// Debug. WriteLine ( ( (double) watch. ElapsedTicks / (double) Stopwatch. Frequency). ToString ());

}

}void AddImage (Int64 itemId, string thumbnailURL, bool isBig)

{img = new Image (itemId, id, thumbnailURL, isBig);. Add (img);

}void SaveImages (string initialDirectory)

{(var image in categoryImages)

{watch = Stopwatch. StartNew ();. Save (initialDirectory);. Stop ();. WriteLine ( ( (double) watch. ElapsedTicks / (double) Stopwatch. Frequency). ToString ());

}();

}

}

}

Модуль NetworkController

using System;System. Collections. Generic;System. Linq;System. Text;System. IO;System. Drawing;System. Threading;System. Diagnostics;grabberMolotok. DBEngine;grabberMolotok. Threading;FANNCategoriesDetector

{NetworkController

{dbEngine; // движок бд<NeuralNetwork> smallNetworks; // маленькие сети<NeuralNetwork> bigNetworks; // большие сетиDictionary<NeuralNetwork, double [] > workResult; // результат работы сетейsmallNetworksInitialized; // флаг инициализации малых сетейbool SmallNetworksInitialized

{{ return smallNetworksInitialized; }

}bigNetworksInitialized; // флаг инициализации больших сетейbool BigNetworksInitialized

{{ return bigNetworksInitialized; }{ bigNetworksInitialized = value; }

}initialDirectory; // рабочая директорияstring InitialDirectory

{{ return initialDirectory; }

}[] smallNetworkLayers = { 3072, 512, 1 }; // слои малых сетей[] bigNetworkLayers = { 12000, 1000, 1 }; // слои больших сетейtrainDataCreationCounter; // счетчик создания данных для обученияtrainDataCreationWorkAmount; // объём работы данных обученияtrainDataCreationThreadCount; // количество потоков данных обученияint TrainDataCreationThreadCount

{{ return trainDataCreationThreadCount; }{ trainDataCreationThreadCount = value; }

}networkTrainCounter; // счетчик обучения сетейnetworkTrainWorkAmount; // объём работы обучения сетейnetworkTrainThreadCount; // количество потоков обучения сетейint NetworkTrainThreadCount

{{ return networkTrainThreadCount; }{ networkTrainThreadCount = value; }

}networkCreateCounter; // счетчик создания сетейnetworkCreateWorkAmount; // объём создания сетейnetworkCreateThreadCount; // потоки создания сетейint NetworkCreateThreadCount

{{ return networkCreateThreadCount; }{ networkCreateThreadCount = value; }

}

#region Событияdelegate void AllTrainDataCreationCompletedEventHandler ();static event AllTrainDataCreationCompletedEventHandler AllTrainDataCreationCompletedEvent;delegate void AllNetworkTrainedEventHandler ();static event AllNetworkTrainedEventHandler AllNetworkTrainedEvent;delegate void AllNetworkCreatedEventHandler ();static event AllNetworkCreatedEventHandler AllNetworkCreatedEvent;delegate void AllNetworkWorkedEventHandler ();static event AllNetworkWorkedEventHandler AllNetworkWorkedEvent;delegate void NetworkCreatedEventHandler ();static event NetworkCreatedEventHandler NetworkCreatedEvent;delegate void NetworkTrainedEventHandler ();static event NetworkTrainedEventHandler NetworkTrainedEvent;OnTrainDataCreationComplete ()

{++;(trainDataCreationCounter == trainDataCreationWorkAmount)

{(AllTrainDataCreationCompletedEvent! = null)();

}

}OnNetworkTrained ()

{++;(networkTrainCounter == networkTrainWorkAmount)

{(AllNetworkTrainedEvent! = null)();

}

}OnNetworkCreated ()

{++;(networkCreateCounter == networkCreateWorkAmount)

{(AllNetworkCreatedEvent! = null)();= true;

}

}

#endregion СобытияNetworkController ()

{.networkCreatedEvent += new NetworkController.networkCreatedEventHandler (this. OnNetworkCreated);.networkTrainedEvent += new NetworkController.networkTrainedEventHandler (this. OnNetworkTrained);. TrainDataCreatedEvent += new NeuralNetwork. TrainDataCreatedEventHandler (this. OnTrainDataCreationComplete);= new grabberMolotok. DBEngine. DBEngine ();= new List<NeuralNetwork> ();= dbEngine. settingsTable. ReadSetting ("initialDirectory");= false;= 0;= 0;= 0;= - 1;= - 1;= - 1;= 8;= 8;= 8;

}int GetNetworkCreationWorkAmount ()

{networks = (new DirectoryInfo (initialDirectory + @"\64x48")). GetFiles ("*. ann");networks. Length;

}CreateSmallNetworks ()

{. Clear ();. WriteLine ("Инициализация нейронных сетей");networks = (new DirectoryInfo (initialDirectory + @"\64x48")). GetFiles ("*. ann");= networks. Length;(var n in networks)

{watch = Stopwatch. StartNew ();net = new NeuralNetwork (smallNetworkLayers);. Create (n. FullName);. TryParse (n. Name. Replace (". ann", ""), out net. id);. category = dbEngine. categoryTable. GetById (net. id);. Add (net);();. Stop ();. WriteLine ( ( (double) watch. ElapsedTicks / (double) Stopwatch. Frequency). ToString ());

}= true;

}CreateBigNetworks ()

{. Clear ();networks = (new DirectoryInfo (initialDirectory + @"\400x300")). GetFiles ("*. ann");(var n in networks)

{net = new NeuralNetwork (bigNetworkLayers);. Create (n. FullName);. TryParse (n. Name. Replace (". ann", ""), out net. id);. category = dbEngine. categoryTable. GetById (net. id);. Add (net);

}= true;

}

#region Паралельная инициализация сетейvoid ParallelCreateSmallNetworks ()

{. Clear ();networksFilesArray = (new DirectoryInfo (initialDirectory + @"\64x48")). GetFiles ("*. ann");<FileInfo> networksFiles = new List<FileInfo> ();. AddRange (networksFilesArray);= networksFiles. Count;preparedList = ThreadHelper. SplitList (networksFiles, networkCreateThreadCount);(int counter = 0; counter < preparedList. Length; counter++)

{parameter = new ParameterForDelegate (preparedList, counter);thread = new Thread (new ParameterizedThreadStart (ParallelCreate));. Start (parameter);. Join (10);

}

}ParameterForDelegate

{List<FileInfo> [] preparedList;int counter;ParameterForDelegate (List<FileInfo> [] preparedList, int counter)

{. preparedList = preparedList;. counter = counter;

}

}ParallelCreate (object parameter)

{<FileInfo> [] preparedList = ( (ParameterForDelegate) parameter). preparedList;counter = ( (ParameterForDelegate) parameter). counter;(int j = 0; j < preparedList [counter]. Count; j++)

{net = new NeuralNetwork (smallNetworkLayers);. Create (preparedList [counter] [j]. FullName);. TryParse (preparedList [counter] [j]. Name. Replace (". ann", ""), out net. id);. Add (net);. Sleep (10);(NetworkCreatedEvent! = null)();

}

}

#endregion Паралельная инициализация сетей/*Dictionary<NeuralNetwork, double [] >*/void Work (object image)

{imageToDetect = (Bitmap) image;<NeuralNetwork, double [] > result = new Dictionary<NeuralNetwork, double [] > ();(! smallNetworksInitialized)();. WriteLine ("Работа нейронных сетей");(var network in smallNetworks)

{watch = Stopwatch. StartNew ();. Add (network, network. Work (imageToDetect));. Stop ();. WriteLine ( ( (double) watch. ElapsedTicks / (double) Stopwatch. Frequency). ToString ());

}= result;. Sleep (50);

// return result;();

}int GetTrainDataCreationWorkAmount ()

{[] trainDirectoryInfo = (new DirectoryInfo (initialDirectory + @"\64x48")). GetDirectories ();

// return trainDirectoryInfo. Length * 2;trainDirectoryInfo. Length;

}int GetParallelTrainDataCreationWorkAmount ()

{[] trainDirectoryInfo = (new DirectoryInfo (initialDirectory + @"\64x48")). GetDirectories ();trainDirectoryInfo. Length;

}void CreateSmallTrainData ()

{();[] trainDirectoryInfo = (new DirectoryInfo (initialDirectory + @"\64x48")). GetDirectories (); // Чтение каталога всех категорий= trainDirectoryInfo. Length;(int i = 0; i < trainDirectoryInfo. Length; i++)

{[] items = trainDirectoryInfo [i]. GetDirectories (); // список товаров в категории<FileInfo> images = new List<FileInfo> (); // изображения товаров в категории<FileInfo> falseImages = new List<FileInfo> (); // изображения товаров в других категориях(var item in items)

{. AddRange (item. GetFiles ("*. jpg"));

}(int j = 0; j < trainDirectoryInfo. Length; j++)

{(j == i);[] falseItems = trainDirectoryInfo [j]. GetDirectories ();(var item in falseItems)

{. AddRange (item. GetFiles ("*. jpg"));

}

}trainImagesCount = (uint) (images. Count + falseImages. Count);net = new NeuralNetwork (smallNetworkLayers);. id = Convert. ToInt32 (trainDirectoryInfo [i]. Name);. CreateTrainDataFile (trainDirectoryInfo [i]. FullName, images, true);

// net. CreateTrainDataFile (trainDirectoryInfo [i]. FullName, images, true, trainImagesCount);

// net. CreateTrainDataFile (trainDirectoryInfo [i]. FullName, falseImages, false, trainImagesCount);

}

}void CreateSmallTrainData (List<DirectoryInfo> trainDirectoryInfo, List<DirectoryInfo> wholeTDI)

{(int i = 0; i < trainDirectoryInfo. Count; i++)

{[] items = trainDirectoryInfo [i]. GetDirectories ();<FileInfo> images = new List<FileInfo> ();<FileInfo> falseImages = new List<FileInfo> ();(var item in items)

{. AddRange (item. GetFiles ("*. jpg"));

}(int j = 0; j < wholeTDI. Count; j++)

{(wholeTDI [j] == trainDirectoryInfo [i]);[] falseItems = wholeTDI [j]. GetDirectories ();(var item in falseItems)

{. AddRange (item. GetFiles ("*. jpg"));

}

}trainImagesCount = (uint) (images. Count + falseImages. Count);net = new NeuralNetwork (smallNetworkLayers);. id = Convert. ToInt32 (trainDirectoryInfo [i]. Name);

// net. CreateTrainDataFile (trainDirectoryInfo [i]. FullName, images, true);. CreateTrainDataFile (trainDirectoryInfo [i]. FullName, images, true, trainImagesCount);. CreateTrainDataFile (trainDirectoryInfo [i]. FullName, falseImages, false, trainImagesCount);

}

}void CreateSmallTrainData (List<DirectoryInfo> trainDirectoryInfo)

{(int i = 0; i < trainDirectoryInfo. Count; i++)

{[] items = trainDirectoryInfo [i]. GetDirectories ();<FileInfo> images = new List<FileInfo> ();(var item in items)

{. AddRange (item. GetFiles ("*. jpg"));

}net = new NeuralNetwork (smallNetworkLayers);. id = Convert. ToInt32 (trainDirectoryInfo [i]. Name);watch = Stopwatch. StartNew ();. CreateTrainDataFile (trainDirectoryInfo [i]. FullName, images, true);. Stop ();. WriteLine ( ( (double) watch. ElapsedTicks / (double) Stopwatch. Frequency / (double) images. Count). ToString ());

}

}void ParallelCreateSmallTrainData ()

{();[] trainDirectoryInfo = (new DirectoryInfo (initialDirectory + @"\64x48")). GetDirectories (); // Чтение каталога всех категорий= trainDirectoryInfo. Length;preparedList = ThreadHelper. SplitList (trainDirectoryInfo. ToList<DirectoryInfo> (), trainDataCreationThreadCount);(List<DirectoryInfo> categories in preparedList)

{thread = new Thread (()

{. WriteLine ("Создание файлов обучения");(categories);

}

);. Start ();. Join (10);

}

}int GetNetworkTrainWorkAmount ()

{[] trainDirectoryInfo = (new DirectoryInfo (initialDirectory + @"\64x48")). GetDirectories (); // Чтение каталога всех категорийcounter = 0;(var category in trainDirectoryInfo)

{trainFilePath = category. FullName + " // " + category. Name +". tr";(File. Exists (trainFilePath))

{++;

}

}counter;

}void TrainSmallNetworks ()

{();= GetNetworkTrainWorkAmount ();[] trainDirectoryInfo = (new DirectoryInfo (initialDirectory + @"\64x48")). GetDirectories (); // Чтение каталога всех категорий(var category in trainDirectoryInfo)

{trainFilePath = category. FullName + "\ + category. Name +". tr";(File. Exists (trainFilePath))

{net = new NeuralNetwork (smallNetworkLayers);. id = Convert. ToInt32 (category. Name);watch = Stopwatch. StartNew ();. Train (trainFilePath);. Stop ();. WriteLine ("Training " + ( (double) watch. ElapsedTicks / (double) Stopwatch. Frequency). ToString ());anotherWatch = Stopwatch. StartNew ();. Save (initialDirectory + @"\64x48);. Stop ();. WriteLine ("Saving " + ( (double) anotherWatch. ElapsedTicks / (double) Stopwatch. Frequency). ToString ());();

}

}

}void TrainSmallNetworks (List<DirectoryInfo> trainDirectoryInfo)

{(var category in trainDirectoryInfo)

{trainFilePath = category. FullName + " // " + category. Name +". tr";(File. Exists (trainFilePath))

{net = new NeuralNetwork (smallNetworkLayers);. id = Convert. ToInt32 (category. Name);

// Stopwatch watch = Stopwatch. StartNew ();. Train (trainFilePath);

// watch. Stop ();

// Debug. WriteLine ( ( (double) watch. ElapsedTicks / (double) Stopwatch. Frequency). ToString ());. Save (initialDirectory + @"\64x48);();

}

}

}void ParallelTrainSmallNetworks ()

{();[] trainDirectoryInfo = (new DirectoryInfo (initialDirectory + @"\64x48")). GetDirectories (); // Чтение каталога всех категорий= GetNetworkTrainWorkAmount ();preparedList = ThreadHelper. SplitList (trainDirectoryInfo. ToList<DirectoryInfo> (), networkTrainThreadCount);(List<DirectoryInfo> categories in preparedList)

{thread = new Thread (()

{. WriteLine ("Обучение сетей");(categories);

}

);. SetApartmentState (ApartmentState. STA);. Start ();. Join (50);

}

}void CascadeTrainSmallNetworks ()

{[] trainDirectoryInfo = (new DirectoryInfo (initialDirectory + @"\64x48")). GetDirectories (); // Чтение каталога всех категорий(var category in trainDirectoryInfo)

{trainFilePath = category. FullName + " // " + category. Name +". tr";net = new NeuralNetwork (smallNetworkLayers);. id = Convert. ToInt32 (category. Name);. CascadeTrain (trainFilePath);. Save (initialDirectory + @"\64x48);

}

}void WipeTrainData ()

{[] trainDirectoryInfo = (new DirectoryInfo (initialDirectory + @"\64x48")). GetDirectories ();(var dir in trainDirectoryInfo)

{tr = dir. GetFiles ("*. tr");

{[0]. Delete ();

}(Exception)

{;

}

}

}void WipeNetworks ()

{ann = (new DirectoryInfo (initialDirectory + @"\64x48")). GetFiles ("*. ann");(var n in ann)

{

{. Delete ();

}(Exception)

{;

}

}

}void Wipe ()

{();();

}

}

}


Министерство образования и науки Российской Федерации Федеральное государственное бюджетное образовательное учреждение Высшего профессионального образован

Больше работ по теме:

КОНТАКТНЫЙ EMAIL: [email protected]

Скачать реферат © 2017 | Пользовательское соглашение

Скачать      Реферат

ПРОФЕССИОНАЛЬНАЯ ПОМОЩЬ СТУДЕНТАМ