[Из песочницы] Нейронные сети для любопытных программистов (с примером на c#)

Так как в заголовке был отмечен «для любопытных программистов», хочу сказать, что и моё любопытство привело к тому, что я, будучи разработчиком мобилных игр, написал такой пост. Я совершенно уверен, что найдутся программисты, которые когда-то думали об искусственных интелектах и это очень хороший шанс для них.

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

пример на java и полезные ссылки
наглядная реализацыя с исползованием ООП

Поскольку теории очень много по этой теме хотелось бы приступить к реализации.

Реализация
using UnityEngine;
using System.Collections;
using System.Xml.Serialization;

public class Neuron {

	[XmlAttribute("weight")]
	public string data;

	[XmlIgnore]
	public int[,] weight; // веса нейронов
	
	[XmlIgnore]
	public int minimum = 50; // порог
	
	[XmlIgnore]
	public int row = 64,column = 64;

	/**
     * Конструктор нейрона, создает веси и устанавливает случайные значения
     */
	public Neuron()
	{
		weight = new int[row,column];
		randomizeWeights();
	}

	/**
     * ответы нейронов, жесткая пороговая
     * @param input - входной вектор
     * @return ответ 0 или 1
     */
	public int transferHard(int[,] input)
	{
		int Power = 0;
		for(int r = 0; r < row;r++)
		{
			for(int c = 0; c < column;c++)
			{
				Power += weight[r,c]*input[r,c];
			}
		}
		//Debug.Log("Power: " + Power);
		return Power >= minimum ? 1 : 0;
	}

	/**
     * ответы нейронов с вероятностями
     * @param input - входной вектор
     * @return n вероятность
     */
	public int transfer(int[,] input)
	{
		int Power = 0;
		for(int r = 0; r < row;r++)
			for(int c = 0; c < column;c++)
				Power += weight[r,c]*input[r,c];

		//Debug.Log("Power: " + Power);
		return Power;
	}

	/**
     * устанавливает начальные произвольные значения весам 
     */
	void randomizeWeights()
	{
		for(int r = 0; r < row;r++)
			for(int c = 0; c < column;c++)
				weight[r,c] = Random.Range(0,10);
	}

	/**
     * изменяет веса нейронов
     * @param input - входной вектор
     * @param d - разница между выходом нейрона и нужным выходом
     */
	public void changeWeights(int[,] input,int d)
	{
		for(int r = 0; r < row;r++)
			for(int c = 0; c < column;c++)
				weight[r,c] += d*input[r,c];
	}

	public void prepareForSerialization()
	{
		data = "";
		for(int r = 0; r < row;r++)
		{
			for(int c = 0; c < column;c++)
			{
				data += weight[r,c] + " ";
			}
			data += "\n";
		}
	}

	public void onDeserialize()
	{
		weight = new int[row,column];

		string[] rows = data.Split(new char[]{'\n'});
		for(int r = 0; r < row;r++)
		{
			string[] columns = rows[r].Split(new char[]{' '});
			for(int c = 0; c < column;c++)
			{
				weight[r,c] = int.Parse(columns[c]);
			}
		}
	}
}

Класс нейронов который содержит weight — двоичный массив весов, minimum — порог функции. Функция transferHard возвращает ответ на входной вектор. Поськольку ответ функции жесткий, я использоваю его для обучения. На мой взгляд это более эффективно обучает нейроны. Я буду очень блогодарен если будут отзывы по этому поводу. Функция transfer возвращает ответ на входной вектор, но с вероятностю, сумма может быть ближе к нулю или отрицательной если нейрон обучен для другово символа.

using UnityEngine;
using System.Collections;
using System.Xml.Serialization;
using System.Xml;
using System.IO;

public class NeuralNetwork {

	[XmlArray("Neurons")]
	public Neuron[] neurons;

	/**
     * Конструктор сети создает нейроны
     */
	public NeuralNetwork()
	{
		neurons = new Neuron[10];

		for(int i = 0;i output[maxIndex])
				maxIndex = i;

		return maxIndex;
	}

	/**
     * функция обучения
     * @param input - входной вектор
     * @param correctAnswer - правильный ответ
     */
	public void study(int[,] input,int correctAnswer)
	{
		int[] correctOutput = new int[neurons.Length];
		correctOutput[correctAnswer] = 1;

		int[] output = handleHard(input);
		while(!compareArrays(correctOutput,output))
		{
			for(int i = 0; i < neurons.Length;i++)
			{
				int dif = correctOutput[i]-output[i];
				neurons[i].changeWeights(input,dif);
			}
			output = handleHard(input);
		}
	}

	/**
     * сравнение двух вектор
     * @param true - если массивы одинаковые, false - если нет
     */
	bool compareArrays(int[] a,int[] b)
	{
		if(a.Length != b.Length)
			return false;

		for(int i = 0;i 0)
		{
			byte[] tempData = new byte[fStream.Length];
			fStream.Read(tempData, 0, tempData.Length);
			
			xml = System.Text.Encoding.ASCII.GetString(tempData);
		}
		fStream.Close();

		if(string.IsNullOrEmpty(xml))
			return new NeuralNetwork();


		NeuralNetwork data;

		XmlSerializer serializer = new XmlSerializer(typeof(NeuralNetwork));
		using(TextReader reader = new StringReader(xml))
		{
			data = serializer.Deserialize(reader) as NeuralNetwork;
		}

		data.onDeserialize();
		
		return data;
	}
}

Класс NeuralNetwork содержит массив нейронов, каждый из них предназначен для конкретного символа. В конструкторе создается массив из десяти элементов, потому что пример сделан для разпознования цифр (0–9). Если вы хотите использовать сеть для распознавания букв то поменяйте размер массива соответствующим образом. Функция handleHard вызывается для обучение нейронов, возвращает массив из нуллей и единиц. Функция getAnswer ответ сети для входного вектора, использует функцию handle для получения массива ответов, каждый элемент массива содержит ответ нейрона с вероятностью. Функция getAnswer выбирает индекс элемента который содержит наибольшую вероятность и возвращает эго как ответ.

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

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

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

Хотелось увидеть различные отзывы на тему и на пост.

Комментарии (0)

© Habrahabr.ru