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

МЕНЮ


Искусственный интеллект
Поиск
Регистрация на сайте
Помощь проекту
Архив новостей

ТЕМЫ


Новости ИИРазработка ИИВнедрение ИИРабота разума и сознаниеМодель мозгаРобототехника, БПЛАТрансгуманизмОбработка текстаТеория эволюцииДополненная реальностьЖелезоКиберугрозыНаучный мирИТ индустрияРазработка ПОТеория информацииМатематикаЦифровая экономика

Авторизация



RSS


RSS новости


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

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

пример на 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 += " "; 		} 	}  	public void onDeserialize() 	{ 		weight = new int[row,column];  		string[] rows = data.Split(new char[]{' '}); 		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<neurons.Length;i++) 			neurons[i] = new Neuron(); 	}  	/**      * функция распознавания символа, используется для обучения      * @param input - входной вектор      * @return массив из нулей и единиц, ответы нейронов      */ 	int[] handleHard(int[,] input) 	{ 		int[] output = new int[neurons.Length]; 		for(int i = 0;i<output.Length;i++) 			output[i] = neurons[i].transferHard(input);  		return output; 	}  	/**      * функция распознавания символа, используется для конечного ответа      * @param input -  входной вектор      * @return массив из вероятностей, ответы нейронов      */ 	int[] handle(int[,] input) 	{ 		int[] output = new int[neurons.Length]; 		for(int i = 0;i<output.Length;i++) 			output[i] = neurons[i].transfer(input); 		 		return output; 	}  	/**      * ответ сети      * @param input - входной вектор      * @return индекс нейронов предназначенный для конкретного символа      */ 	public int getAnswer(int[,] input) 	{ 		int[] output = handle(input); 		int maxIndex = 0; 		for(int i = 1; i < output.Length;i++) 			if(output[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<a.Length;i++) 			if(a[i] != b[i]) 				return false;  		return true; 	} 	 	void prepareForSerialization() 	{ 		foreach(Neuron n in neurons) 			n.prepareForSerialization(); 	}  	void onDeserialize() 	{ 		foreach(Neuron n in neurons) 			n.onDeserialize(); 	}  	public void saveLocal() 	{ 		prepareForSerialization();  		XmlSerializer serializer = new XmlSerializer(this.GetType()); 		FileStream stream = new FileStream(Application.dataPath + "/NeuralNetwork.txt", FileMode.Create); 		XmlWriter writer = new XmlTextWriter(stream, new System.Text.ASCIIEncoding()); 		using(writer) 		{ 			serializer.Serialize(writer, this); 		} 	}  	public static NeuralNetwork fromXml() 	{ 		string xml = ""; 		FileStream fStream = new FileStream(Application.dataPath + "/NeuralNetwork.txt", 		                                    FileMode.OpenOrCreate); 		if(fStream.Length > 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 выбирает индекс элемента который содержит наибольшую вероятность и возвращает эго как ответ.

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

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

Заключение


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

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

Источник: habrahabr.ru

Комментарии: