Методические указания
по проведению лабораторной работы N2

"Программирование искусственной нейронной сети"

по курсу

"Искусственные нейронные сети"

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

Теоретическая часть

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

Пусть дано прямоугольное изображение, каждый пиксел которого характеризуется своей яркостью. Изображение разбивается на 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). Вследствие линейности функций активации и однонаправленности распространения сигналов имеем:

Hk=W(2)*W(1)*Xk.

Обучение сети, состоящее в оптимальном подборе весов, составляющих матрицы W(1) и W(2), подразумевает минимизацию целевой функции в виде:

E(W)=(1/2)*sum[k=1:p](sum[i=1:N]((hki-xki)2)).

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

Wk+1=Wk-nu*gradE(Wk).

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

дE(W)/дw(2)il=(yi-di)*df(u(2)i)/du(2)i*gl,
где u(2)i=sum[l=0:L](w(2)il*gl).

С учетом линейности функций активации выходного слоя нейронов f(u(2)i) выражения для частных производных упрощаются:

дE(W)/дw(2)il=(yi-di)*gl.

Компоненты вектора градиента для весов первого слоя нейронов определяются более сложно:

дE(W)/дw(1)lj = sum[i=1:M]((yi-di)*dyi/dgl*dgl/dw(1)lj)
= sum[i=1:M]((yi-di)*w(2)il*df(u(1)l)/du(1)l*xj).

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

дE(W)/дw(1)lj = sum[i=1:M]((yi-di)*w(2)il*xj).

Для отладки программы, реализующей нейронную сеть, воспользуемся фотографией "Экзамен", представленной ниже.

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

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

Ниже представлены результаты работы нейронной сети для различных значений параметров Nh, Nv и L (во всех случаях использовался единственный цикл обучения).

На приведенном выше рисунке даны результаты работы нейронной сети при Nh=2, Nv=2 и L=2.

На приведенном выше рисунке даны результаты работы нейронной сети при Nh=4, Nv=4 и L=4.

На приведенном выше рисунке даны результаты работы нейронной сети при Nh=4, Nv=4 и L=2.

На приведенном выше рисунке даны результаты работы нейронной сети при Nh=8, Nv=8 и L=6.

Практическая часть

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);
  }