Распознавание слов естественного языка с использованием нейросетей

Автор работы: Пользователь скрыл имя, 12 Мая 2012 в 21:54, курсовая работа

Краткое описание

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

Содержание работы

Введение
1. Анализ нейронных сетей
1.1 Выбор разновидности сети
1.2 Модель многослойного персептрона с обучением по методу обратного распространения ошибки
1.3 Постановка задачи
2. Проектирование библиотеки классов для реализации нейросети и тестовой программы
2.1 Программная реализация нейросети обратного распространения ошибки
2.2 Класс перевода текста в двоичный вид
2.3 Класс хеш-таблицы и методов работы с ней
2.4 Класс разбиения текста на лексемы и распознавания
2.5 Описание тестирующей программы
2.6 Результаты тестирования
3. Руководство программисту
Заключение
Список используемой литературы
Приложения

Содержимое работы - 1 файл

ф1.docx

— 220.45 Кб (Скачать файл)

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

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

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

3. Вычислить  ошибки для выходного слоя (calculate_output_layer_errors). При этом используем формулу (7) для каждого i-ого значения выходного слоя. Ниже представлена соответствующая функция:

 

private void calculate_output_layer_errors()

{ for (int j = 0; j < MAX_OUT; j++)

{ ol[j].E = (desired[j] - ol[j].a) * ol[j].a * (1 - ol[j].a); } }

 

Вычисление ошибки для скрытого и входного слоев производится методами calculate_input_layer_errors и calculate_hidden_layer_errors по формуле (8). Код соответствеющей функции для входного слоя предтсавлен ниже:

 

private void calculate_input_layer_errors()

{

double sum;

for (int i = 0; i < MAX_INP; i++)

{

sum = 0; // {Сумма ошибок скрытого слоя}

for (int j = 1; j < MAX_HID; j++)

{ sum = sum + hl[j].E * hl[j].w[i]; }

ipl[i].E = ipl[i].a * (1 - ipl[i].a) * sum;

}

}

Используя формулы (9), (10), (11) получим функцию, обучающую весовые коэффициенты и пороговые уровни:

 

private void weight_change()

{ //i обозначает нейрон скрытого слоя, j - выходного

for (int j = 0; j < MAX_OUT; j++) //выходной слой

{ for (int i = 0; i < MAX_HID; i++) //Подстройка}

{ ol[j].change[i] = BETA * ol[j].E * hl[i].a + M * ol[j].change[i];

ol[j].w[i] = ol[j].w[i] + ol[j].change[i]; }

//Подстройка значения порога

ol[j].t_change = BETA * ol[j].E * 1 + M * ol[j].t_change;

ol[j].threshold = ol[j].threshold + ol[j].t_change; // }

//Модифицируем  веса между входным слоем и  скрытым слоем

//Модифицируем  веса между входами и входным  слоем 

… } }

 

Далее объединим  вышеуказанные функции в одном  методе back_propogate().

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

 

public void train_the_network()

{ blank_changes();//Очистка предыдущих значений changes}

for (int loop = 0; loop < num_cycles; loop++)

{ for (int pat = 0; pat < MAX_PAT; pat++)

{ for (int i = 0; i < MAX_INP; i++) //Копирование входного образа}

{ test_pat[i] = INP_PATTERNS[pat, i]; } /в массив 'test_pat'

for (int i = 0; i < MAX_OUT; i++) //Копирование выходного образа

{ desired[i] = OUT_PATTERNS[pat, i]; } //в массив'desired'

run_the_network();//Определение  выходов сети

back_propagate(); } }

AddWeightsToFile(); }

 

Для очистки  предыдущих значений используется функция blank_changes.

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

 

2.2 Класс перевода текста в двоичный вид

 

Данный класс предназначен для бинаризации исходных данных (слов), т.е. перевода слов с естественного языка в набор единиц и нулей. Данная процедура является необходимой, т.к. нейронная сеть обратного распространения ошибки работает только с двоичными данными. UML диаграмма класса Binarization представлена на рисунке 7.

 

Класс Binarization

Закрытые поля

string[] sLetter;

int iLengthPattern;

Закрытые методы

private string DecToBin(string value)

Открытые методы

public double[] GetBinarizeWord(string sWord)

public double[,] GetBinarizeText(out double[,] OUT_PATTERNS, out int max_pat, out int iLengthPattern1)

public Binarization(string[] sLetter1)


Рисунок 7 –UML-диаграмма  класса Binarization

 

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

Алгоритм работы методов  GetBinarizeWord и GetBinarizeText данного класса в общем состоит из следующих этапов:

  • кодировка слова: суммирование произведений ASCII-кодов букв на i+4, где i – номер буквы в слове;
  • перевод полученного десятичного числа в двоичный вид при помощи метода DecToBin;
  • обработка полученных данных.

 

2.3 Класс хеш-таблицы и методов работы с ней

 

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

 

Класс Hash

Закрытые поля

Dictionary<int, string> predlog = new Dictionary<int, string>();

Dictionary<int, string> narechie = new Dictionary<int, string>();

Dictionary<int, string> deepr = new Dictionary<int, string>();

Dictionary<int, string> soyuz = new Dictionary<int, string>();

Dictionary<int, string> mest = new Dictionary<int, string>();

Dictionary<int, string> iskl = new Dictionary<int, string>();

string[] sConstant = { "predlog", "narechie", "deepr", "soyuz", "mest", "iskl" };

Закрытые методы

private int HashFunction(string sInfo)

Открытые методы

public bool CheckHash(string sInfo, string sHash_name)

public void AddLetterInHashAndFile(string sLetter, string sClass,bool Flag)

public void AddToHash(string sInfo, string sHash_name)

public void ReadFileInHash(string sNamefile)

public void WriteWordInFile(string sInfo, string sNamefile)

public Hash()


Рисунок 8 – UML диаграмма класса Hash

 

Полями данного класса являются хеш-таблицы – predlog (содержит предлоги), narechie (наречия), deepr (деепричастия), soyuz (союзы), mest (местоимения), iskl (существительные, глаголы, прилагательные сложные для распознавания).

Класс также содержит методы:

  • HashFunction – значение хеш-функции для текущего слова;
  • CheckHash – проверка наличия записи в хеш-таблице;
  • AddLetterInHashAndFile – классификация и добавление нового слова в хеш-таблицу, а также запись в файл;
  • AddToHash – добавление слова в хеш-таблицу;
  • ReadFileInHash и WriteWordInHash – чтение слов из файла и запись слова в файл соответственно.

 

2.4 Класс разбиения текста на лексемы и распознавания

 

Данный класс является главным. Его задача – вычленение лексем из текста и их дальнейшее распознавание. В нем используются объекты всех вышеописанных классов. UML-диаграмма класса Analization представлена на рисунке 9.

 

Класс Analization

Закрытые поля

List<Results> results = new List<Results>();

bool flag_oy = false;

bool flag_om = false;

bool flag_im = false;

bool flag_em = false;

Bool flag_ie=false;

bool flag_mi=false;

Закрытые методы

private void AddEtalonLetter()

private string GetNeuroResult(string sLetter, string sFileName, int N_HID, double beta, double m, int Epoch, bool flag)

private string Scaning(string sLetter, int N_HID, double beta, double m, int Epoch, bool flag)

Открытые методы

public static void AddToFile(string sLetter, string sFile)

public string BigToSmall(string letter)

public Analization(string sText, int N_HID, double beta, double m, int Epoch, bool flag)

public List<Results> GetResult()


Рисунок 9 – UML-диаграмма класса Analization

 

Параметрами конструктора являются:

  • текст для анализа – sText;
  • параметры нейросети N_HID, beta, m, Epoch;
  • индикатор необходимости обучения нейросети – flag.

Из всех вышеперечисленных  методов наиболее важными являются: конструктор, Scaning и GetNeuroResult.

Анализируемый текст сначала  подается в конструктор. Там он разбивается  на отдельные лексемы, тип которых  либо определяется сразу (если это знак препинания или имя собственное), либо посредством метода Scaning. Код данного метода представлен ниже:

 

private string Scaning(string sLetter, int N_HID, double beta, double m, int Epoch, bool flag)

{ Hash hash = new Hash();

string result = "существительное";//результат

string[] znaks = { "с", "п", "г" };

for (int i = 0; i < znaks.Length; i++)//поиск существительных, прилагательных и глаголов-исключений, сохраненных в хеш-таблице

{ if (hash.CheckHash(sLetter + znaks[i].ToString(), "iskl") == true)

{ switch (znaks[i])

{ case "с": result = "существительное";//если в конце слова буква с – возвращаем результат

return result;

case "п": result = "прилагательное";

return result;

case "г": result = "глагол";

return result; } } }

if (hash.CheckHash(sLetter, "predlog") == true)//проверяем, является ли слово предлогом (ищем в соответствующей хеш-таблице

{ result = "предлог";//если слово есть в хеш-таблице – возвращаем результат

return result; }

//Для  местоимений, союзов, деепричастий  и наречий аналогично

if (String.Compare(sLetter, "не") == 0 || String.Compare(sLetter, "бы") == 0)

{ result = "частица";

return result; }

if (sLetter.Length < 2)

{ return "предлог"; }

//--------------------------------------------------------------------

string[] pril = {"ий","ый","ая","яя","го","ую","ое","их","ых","ым"};//массив окончаний прилагательных

string[] glagol = {"ит","ат","ят","ут","ют","ул","ял","ал","ли","ла","ег","ел","сь","ыл","ил"};//глаголов

string[] prich = {"вший","шими","вшая","вшем","вшие","ящий","ящая","ящие","щими","ющий","ющая","ющие","ущий","ущая","ущие","ащий","ащая","ащие","шего","щего"};//окончаний и суффиксов причастий

string okonchanie= (sLetter[sLetter.Length - 2].ToString() + sLetter[sLetter.Length - 1].ToString());

if (Array.IndexOf(pril,okonchanie)!=-1)//если окончание слова содержится в массиве окончаний прилагательных переходим к проверке суффикса

{string ok_i_suff = sLetter[sLetter.Length - 4].ToString() + sLetter[sLetter.Length - 3].ToString() + okonchanie;

if (Array.IndexOf(prich,ok_i_suff)!= -1)//ищем в массиве суффиксов и окончаний причастий

{ return "причастие"; //если есть – результат причастие }

return "прилагательное"; //если нет - прилагательное }

else

if (String.Compare(okonchanie, "ом") == 0)//если окончание -ом

{ string res= GetNeuroResult(sLetter,"-ом",N_HID,beta,m,Epoch,flag_om);//распознаем слово нейросетью

flag_om = true;//при повторном поступлении слова на –ом нейросеть повторно обкчаться не будет

return res; }

else

//Аналогично  для –ем, -им, -ой, -ие, -ми.

….}

 

Метод Scaning логически можно разделить на 3 блока:

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

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

  • при помощи метода IndexOf класса Array определяется наличие в соответствующем массиве (массиве окончаний глаголов - glagol, прилагательных - pril) данного окончания;
  • если это окончание прилагательного или -ся то критерий поиска изменяется до идентификации по паре суффикс-окончание: определяется наличие данной пары в массиве prich (причастие);
  • после проведения вышеуказанных операций функция возвращает тип лексемы: глагол, прилагательное или причастие;
  • в случае, если окончание не найдено ни в одном из массивов, то тип лексемы определяется как существительное;
  • если слово оканчивается на -ие, -ми, -ем, -им, -ом то переходим к третьему блоку.

В третьем блоке в  зависимости от окончания слова  производится вызов функции private string GetNeuroResult(string sLetter, string sFileName, int N_HID, double beta, double m, int Epoch, bool flag) параметрами:

  • sLetter – лексема,
  • sFileName – имя файла с обучающей выборкой,
  • N_HID – количество скрытых нейронов,
  • beta – коэффициент обучения,
  • m – момент,
  • Epoch – количество эпох обучения,
  • flag – логическая переменная, в значении «истина» означающая, что анализ будет производиться без обучения;

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