Цель работы - создание программы, реализующей искусственную нейронную сеть; разработка процедуры обучения сети; использование полученных результатов для решения тестовых задач сжатия данных, классификации и аппроксимации.
Модели различных типов искусственных нейронных сетей и методы их обучения описаны в учебном пособии "Искусственные нейронные сети". В теоретической части данного пособия в качестве примера рассматривается простейшая двухслойная сеть с линейными функциями активации, используемая для решения задачи сжатия данных с потерями.
Пусть дано прямоугольное изображение, каждый пиксел которого характеризуется своей яркостью. Изображение разбивается на p прямоугольных кадров размером Nh x Nv каждый. Кадр сжимается в вектор данных размерностью L (L<Nh*Nv), который затем восстанавливается (например, после хранения или передачи по медленным каналам связи) в кадр того же размера Nh x Nv.
Решение этой задачи возможно с использованием сети, структурная схема которой представлена ниже.

Здесь xkj, j=1,2, ..., N, N=Nh*Nv - значение яркости j-ого пикселя в k-ом кадре, k=1, 2, ..., p.
Сжатие (компрессия) данных осуществляется первым слоем нейронов, а восстановление (декомпрессия) - выходным. Сеть является автоассоциативной, поскольку ее выходной вектор Hk должен совпадать с входным Xk.
Веса первого слоя нейронов в матричной форме обозначаются W(1), а выходного слоя - W(2). Вследствие линейности функций активации и однонаправленности распространения сигналов имеем:
Обучение сети, состоящее в оптимальном подборе весов, составляющих матрицы W(1) и W(2), подразумевает минимизацию целевой функции в виде:
Для отыскания минимума этой целевой функции будем использовать метод обратного распространения ошибки в режиме онлайн. В рамках данного метода уточнение весовых коэффициентов производится формулой метода градиента:
Частные производные целевой функции по весам нейронов выходного слоя имеют следующий вид:
С учетом линейности функций активации выходного слоя нейронов f(u(2)i) выражения для частных производных упрощаются:
Компоненты вектора градиента для весов первого слоя нейронов определяются более сложно:
Опять линейность функций активации и для первого слоя нейронов позволяет упростить выражения до следующего вида:
Для отладки программы, реализующей нейронную сеть, воспользуемся фотографией "Экзамен", представленной ниже.

Из данной цветной фотографии получим образ в формате png в градациях серого размером 256x256 пикселей, как это показано ниже.

Для манипулирования данными, составляющими изображение в формате png, наибольшее распространение получили средства прикладных библиотек libgd (http://www.boutell.com/gd) и libpng (http://www.libpng.org). В данном учебном пособии используются функции библиотеки libpng, в Приложении приведен пример программы, осуществляющей считывание изображения из png-файла, модификацию этого изображения и его запись в выходной png-файл.
Ниже представлены результаты работы нейронной сети для различных значений параметров Nh, Nv и L (во всех случаях использовался единственный цикл обучения).




1. Лабораторная работа выполняется в среде ОС Linux с использованием компилятора gcc/g++ языка программирования C/C++. Для создания графических иллюстраций рекомендуется использовать утилиту gnuplot.
2. Разработать, используя язык C/C++, программу, моделирующую поведение искусственной нейронной сети указанного преподавателем типа и обеспечивающую ее обучение для решения задач сжатия данных с потерями, классификации и аппроксимации. Ниже представлена таблица вариантов заданий.
| Номер варианта | Тип нейронной сети | Назначение сети |
|---|---|---|
| 1 | Двухслойная сеть с линейными функциями активации | Сжатие изображения |
| 2 | Сеть с самоорганизацией на основе конкуренции | Сжатие изображения |
| 3 | Сеть с самоорганизацией на основе конкуренции | Классификация данных по алгоритму Кохонена |
| 4 | Сеть с самоорганизацией на основе конкуренции | Классификация данных по алгоритму нейронного газа |
| 5 | Многослойный персептрон (бинарные функции активации) | Аппроксимация данных |
| 6 | Многослойный персептрон (сигмоидальные функции активации) | Аппроксимация данных |
| 7 | Радиальная нейронная сеть | Аппроксимация данных |
3. Отладить модель нейронной сети и процедуру ее обучения на произвольных данных. В заданиях, связанных с обработкой изображений, необходимо подготовить, используя любой растровый графический редактор (например, gimp) несколько изображений в градациях серого (глубина - 8 бит) в формате png с размерами кратными 16. В задачах классификации для отладки можно воспользоваться вариантами распределения данных из лабораторной работы "Программирование искусственного нейрона".
4. Обучить разработанную нейронную сеть на предложенном преподавателем варианте данных и проверить ее работоспособность.
5. Выполнить все модификации в программе и исходных данных, указанные преподавателем.
6. Оформить отчет по лабораторной работе с использованием языка разметки HTML (все иллюстрации должны быть представлены в формате png).
1. Описание реализованной модели нейронной сети и процедуры ее обучения.
2. Описание (графическое или табличное) обучающих данных.
3. Численные значения, характеризующие начальное состояние, ход обучения и его результат (например, начальные и итоговые значения входных весов нейронов, величина коэффициента обучения, количество циклов обучения и т.п.).
4. Графическое представление результатов обучения нейрона.
5. Исходный текст программы.
Здесь приведен текст программы на языке C, иллюстрирующей использование прикладной библиотеки libpng для манипулирования файлами в формате png. Программа считывает входной png-файл, содержащий изображение в градациях серого с глубиной 8 бит, "инвертирует" яркость каждого пикселя и записывает полученное изображение в выходной png-файл.
/*
Команда компиляции и компоновки:
gcc -o pngexam pngexam.c -lpng -lz -lm
*/
#include <stdlib.h>
#include <stdio.h>
#include <png.h>
#define PNG_BYTES_TO_CHECK 4
int main (int argc, char *argv[]) {
png_structp png_read_ptr;
png_infop info_read_ptr;
png_structp png_write_ptr;
png_infop info_write_ptr;
png_uint_32 width, height;
int bit_depth, color_type, interlace_type;
int compression_type, filter_method;
int row, col;
png_bytep *row_pointers;
char sigBuf[PNG_BYTES_TO_CHECK];
FILE *fpIn;
FILE *fpOut;
fpIn = stdin;
if (argc > 1) {
if ((fpIn = fopen(argv[1], "r")) == NULL) {
perror (argv[1]);
exit (1);
};
};
if (fread(sigBuf, 1, PNG_BYTES_TO_CHECK, fpIn) != PNG_BYTES_TO_CHECK) {
fclose (fpIn);
exit (2);
};
/* Проверка первых PNG_BYTES_TO_CHECK байт заголовка png-файла */
if ( png_sig_cmp(sigBuf, (png_size_t)0, PNG_BYTES_TO_CHECK) ) {
fclose (fpIn);
exit (3);
};
png_read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_read_ptr == NULL) {
fclose(fpIn);
exit (2);
};
info_read_ptr = png_create_info_struct(png_read_ptr);
if (info_read_ptr == NULL) {
fclose(fpIn);
png_destroy_read_struct(&png_read_ptr, png_infopp_NULL, png_infopp_NULL);
exit (3);
};
if ( setjmp( png_jmpbuf(png_read_ptr) ) ) {
/* Переход в эту точку означает возникновение ошибки при чтении png-файла */
/* Освободить память, ассоциированную с png_read_ptr и info_read_ptr */
png_destroy_read_struct(&png_read_ptr, &info_read_ptr, png_infopp_NULL);
fclose(fpIn);
exit (4);
};
png_init_io(png_read_ptr, fpIn);
/* Информировать о том, что PNG_BYTES_TO_CHECK байт уже прочитано */
png_set_sig_bytes(png_read_ptr, PNG_BYTES_TO_CHECK);
png_read_png(png_read_ptr, info_read_ptr, PNG_TRANSFORM_IDENTITY, png_voidp_NULL);
fclose(fpIn);
png_get_IHDR(png_read_ptr, info_read_ptr, &width, &height, &bit_depth,
&color_type, &interlace_type, &compression_type, &filter_method);
printf ("Ширина = %d, высота = %d\n", width, height);
printf ("Тип цвета = %d, глубина цвета = %d\n", color_type, bit_depth);
printf ("Количество байт в строке = %d\n", png_get_rowbytes(png_read_ptr, info_read_ptr));
if (color_type != 0) {
fprintf (stderr, "Не умею работать с типом цвета %d (только 0)\n", color_type);
exit (11);
};
if (bit_depth != 8) {
fprintf (stderr, "Не умею работать с глубиной цвета %d (только 8)\n", bit_depth);
exit (11);
};
row_pointers = png_get_rows (png_read_ptr, info_read_ptr);
/*--- Получение негатива исходного изображения ---*/
for (row = 0; row < height; row++) {
for (col = 0; col < width; col++) {
row_pointers[row][col] ^= 0xFF;
};
};
/*------ Запись png-файла -----*/
fpOut = stdout;
if (argc > 2) {
if ((fpOut = fopen(argv[2], "w")) == NULL) {
perror (argv[2]);
exit (5);
};
};
png_write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_write_ptr == NULL) {
fclose(fpOut);
exit (6);
};
info_write_ptr = png_create_info_struct(png_write_ptr);
if (info_write_ptr == NULL) {
fclose(fpOut);
png_destroy_write_struct(&png_write_ptr, png_infopp_NULL);
exit (7);
};
if ( setjmp (png_jmpbuf(png_write_ptr) ) ) {
fclose(fpOut);
png_destroy_write_struct(&png_write_ptr, &info_write_ptr);
exit (8);
};
png_set_IHDR(png_write_ptr, info_write_ptr, width, height, bit_depth,
color_type, interlace_type, compression_type, filter_method);
png_set_rows (png_write_ptr, info_write_ptr, row_pointers);
png_init_io(png_write_ptr, fpOut);
png_write_png(png_write_ptr, info_write_ptr, PNG_TRANSFORM_IDENTITY, png_voidp_NULL);
png_destroy_read_struct(&png_read_ptr, &info_read_ptr, png_infopp_NULL);
fclose(fpOut);
exit (0);
}