<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Mind Unpacked &#187; C++</title>
	<atom:link href="http://mindunpacked.com/tag/c/feed/" rel="self" type="application/rss+xml" />
	<link>http://mindunpacked.com</link>
	<description>informatica.elettronica.chimica.new stuff</description>
	<lastBuildDate>Tue, 22 Dec 2009 17:35:13 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.6</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<image>
<link>http://mindunpacked.com</link>
<url>http://mindunpacked.com/wp-content/plugins/maxblogpress-favicon/icons/favicon-2.ico</url>
<title>Mind Unpacked</title>
</image>
		<item>
		<title>Matrici e filtri di convoluzione</title>
		<link>http://mindunpacked.com/2009/matrici-e-filtri-di-convoluzione/</link>
		<comments>http://mindunpacked.com/2009/matrici-e-filtri-di-convoluzione/#comments</comments>
		<pubDate>Sat, 10 Jan 2009 17:23:34 +0000</pubDate>
		<dc:creator>Francesco</dc:creator>
				<category><![CDATA[Informatica]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[filtri convoluzione]]></category>
		<category><![CDATA[image processing]]></category>
		<category><![CDATA[matrici convoluzione]]></category>

		<guid isPermaLink="false">http://mindunpacked.com/?p=310</guid>
		<description><![CDATA[Per matrice di convoluzione si intende una matrice che viene applicata ad un&#8217;immagine per ottenere una seconda immagine con caratteristiche particolari. I filtri di convoluzione sono appunto quei filtri, presenti in quasi tutti i programmi di grafica, che modificano l&#8217;immagine imprimendogli alcuni effetti come per esempio la sfocatura (blur), una maggiore definizione (sharpen), etc&#8230; quasi [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify;">Per <strong>matrice di convoluzion</strong>e si intende una matrice che viene applicata ad un&#8217;immagine per ottenere una seconda immagine con caratteristiche particolari. I <strong>filtri di convoluzione</strong> sono appunto quei filtri, presenti in quasi tutti i programmi di grafica, che modificano l&#8217;immagine imprimendogli alcuni effetti come per esempio la sfocatura (blur), una maggiore definizione (sharpen), etc&#8230; quasi tutti questi filtri fanno uso di matrici di convoluzione, e vedremo come creare un semplice programma in C++ che, data un&#8217;immagine in input ed una matrice di convoluzione produca l&#8217;immagine di output.</p>
<p style="text-align: justify"><span id="more-310"></span> Sebbene le matrici di convoluzione, chiamate anche &#8220;<strong>kerne</strong><strong>l</strong>&#8220;, possano essere di qualsiasi dimensione, le piu&#8217; usate sono quelle 5&#215;5 e <strong>3x</strong><strong>3</strong>. In questo articolo prenderemo in considerazione solo le seconde, che sono sufficienti a creare una grande varieta&#8217; di effetti. La matrice va applicata separatamente ad ogni canale dell&#8217;immagine (R, G, B) nel seguente modo. Supponiamo di operare esclusivamente sul canale R, visto che le operazioni sono analoghe agli altri canali, e di avere pixel con i valori indicati nella matrice a sinistra a cui vogliamo applicare la matrice di convoluzione presente a destra:</p>
<table style="text-align: center;" border="0">
<tbody>
<tr>
<td>
<table style="text-align: center;" border="0">
<tbody>
<tr>
<td>255</td>
<td>180</td>
<td>100</td>
</tr>
<tr>
<td>125</td>
<td><span style="color: #ff0000;">175</span></td>
<td>150</td>
</tr>
<tr>
<td>0</td>
<td>123</td>
<td>20</td>
</tr>
</tbody>
</table>
</td>
<td>
<table border="0">
<tbody>
<tr>
<td>0</td>
<td>0</td>
<td>0</td>
</tr>
<tr>
<td>0</td>
<td>1</td>
<td>0</td>
</tr>
<tr>
<td>0</td>
<td>0</td>
<td>0</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<p>Il pixel evidenziato in rosso e&#8217; quello su cui stiamo lavorando in questo momento, mentre la matrice a destra e&#8217; il nostro kernel. Per applicare il filtro di convoluzione sul pixel dobbiamo immaginare di sovrapporre l&#8217;elemento centrale della matrice kernel con il pixel che stiamo considerando e di fare la somma di tutti i prodotti degli elementi sovrapposti. In poche parole dobbiamo moltiplicare gli elementi corrispondenti tra le due matrici e sommare tutti i risultati. Notate che non stiamo effettuando una normale moltiplicazione tra matrici (cioe&#8217; un prodotto riga per colonna)!</p>
<p style="text-align: justify">Nel nostro caso il calcolo e&#8217;:</p>
<p style="text-align: justify">255*0 + 180*0 + 100*0 + 125*0 + 175*1 + 150*0 + 0*0 + 123*0 + 20*0 == 175</p>
<p style="text-align: justify">La matrice di convoluzione che abbiamo scelto, potrebbe essere paragonata alla matrice identita&#8217; nel caso di un prodotto tra matrici. Come la matrice identita&#8217; non cambia il risultato, cosi&#8217; questa matrice  fornisce come risultato lo stesso pixel e quindi l&#8217;immagine di output rimane invariata. Ovviamente questo e&#8217; un caso particolare, e alla fine dell&#8217;articolo vedremo alcuni degli effetti prodotti da altre matrici particolari.</p>
<p style="text-align: justify">Comunque, quando la matrice di convoluzione viene applicata a tutti i pixel dell&#8217;immagine il lavoro e&#8217; terminato ed abbiamo ottenuto la nostra immagine modificata. Vediamo alcune parti del codice in C++ che trovate allegato alla fine dell&#8217;articolo. Ah, il codice fa uso, come al solito, delle librerie EasyBMP per la gestione delle BMP.</p>
<pre class="brush: cpp;">int mat[DIM][DIM];

typedef struct pixel {
	int red, green, blue;
};
</pre>
<p><center><script type="text/javascript">
heyos_ad_user = 11334;
heyos_ad_type = "G";
heyos_ad_format = "1";
heyos_color_border = "23292b";
heyos_color_bg = "23292b";
heyos_color_link = "FFFFFF";
heyos_color_text = "21b8ca";
heyos_color_url = "21b8ca";
</script>
<script type="text/javascript" src="http://admaster.heyos.com/core/bnr.js"></script></center></p>
<p style="text-align: justify">Creiamo una matrice DIMxDIM (dove DIM = 3 nel nostro caso), che sara&#8217; la nostra matrice di convoluzione, e creiamo un nostro tipo per descrivere i pixels. Dopo aver fatto inserire all&#8217;utente i 9 valori degli elementi della matrice, possiamo iniziare i calcoli. Nelle righe 38-56 (non le scrivo qua perche&#8217; vengono formattate male) svolgiamo i calcoli veri e propri. Gli indici i e j sono le coordinate x e y del pixel che stiamo esaminando; notate che escludiamo i pixel appartenenti al bordo esterno dell&#8217;immagine semplicemente perche&#8217; non hanno 8 pixel confinanti come tutti gli altri, e quindi verrebbe piu&#8217; difficile applicare la matrice perche&#8217; dovremmo escludere alcuni pixel dal conteggio; il risultato non cambia di molto.</p>
<p style="text-align: justify">I nuovi valori dei pixel vengono salvati in un array di oggetti pixel (il typedef che abbiamo definito poco piu&#8217; su). Quello che ci manca è riportare questi valori in un intervallo 0&#8230;255. Sappiamo infatti che 255 e&#8217; il valore massimo per ogni componente di un pixel, ma dall&#8217;applicazione del nostro filtro, potremmo avere (e&#8217; spesso e&#8217; cosi&#8217;) valori che superano questa soglia. Per fare cio&#8217; calcoliamo la somma di tutti gli elementi della matrice di convoluzione e dividiamo tutti i valori di output per questa somma. Se dopo questa operazione ci saranno ulteriori valori &gt; 255, li imposteremo uguali a 255, cosi&#8217; come imposteremo a 0 quelli &lt; 0.</p>
<p style="text-align: justify">Vediamo un esempio:</p>
<table border="0">
<tbody>
<tr>
<td><a href="http://www.mindunpacked.com/risorse/2.bmp"><img class="alignnone" title="Immagine originale" src="http://www.mindunpacked.com/risorse/2_th.bmp" alt="" width="200" height="183" /></a></td>
<td>
<p style="text-align: center">MATRICE DI CONVOLUZIONE</p>
<p style="text-align: center">0 -1  0</p>
<p style="text-align: center">-1  4  -1</p>
<p style="text-align: center">0  -1  0</p>
</td>
<td><a href="http://www.mindunpacked.com/risorse/out.bmp"><img class="alignnone" title="Risultato" src="http://www.mindunpacked.com/risorse/out_th.bmp" alt="" width="200" height="183" /></a></td>
</tr>
</tbody>
</table>
<p style="text-align: justify">In questo esempio, e&#8217; stata applicata all&#8217;immagine una matrice per individuare i bordi (edge detection). Le immagini sono piuttosto pesanti essendo BMP e quindi non compresse.</p>
<p style="text-align: justify">Su Internet si trovano facilmente altre matrici di convoluzione associate a risultati particolari. Ecco il <a title="Codice C++ matrici di convoluzione" href="http://www.mindunpacked.com/risorse/matrix.zip" target="_self">codice del programma</a>. Alla prossima.</p>
<p style="text-align: justify">
]]></content:encoded>
			<wfw:commentRss>http://mindunpacked.com/2009/matrici-e-filtri-di-convoluzione/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Reti neurali attraverso algoritmi genetici in C++. Parte VI</title>
		<link>http://mindunpacked.com/2008/reti-neurali-attraverso-algoritmi-genetici-in-c-parte-vi-ultima/</link>
		<comments>http://mindunpacked.com/2008/reti-neurali-attraverso-algoritmi-genetici-in-c-parte-vi-ultima/#comments</comments>
		<pubDate>Tue, 30 Dec 2008 17:57:53 +0000</pubDate>
		<dc:creator>Francesco</dc:creator>
				<category><![CDATA[Informatica]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[Intelligenza artificiale]]></category>
		<category><![CDATA[Reti neurali]]></category>

		<guid isPermaLink="false">http://mindunpacked.com/?p=345</guid>
		<description><![CDATA[Applicazioni.
Le reti neurali hanno diverse applicazioni e spaziano in diversi campi. In questo paragrafo elencherò alcune applicazioni interessanti che ho trovato sulla rete e poi mostrerò come è possibile creare un molto rudimentale sistema di riconoscimento dii  immagini, capace di riconoscere i numeri da 0 a 9.

Alcune applicazioni sono:
Vita artificiale: la vita artificiale tenta [...]]]></description>
			<content:encoded><![CDATA[<p align="center"><strong>Applicazioni.</strong></p>
<p align="justify">Le reti neurali hanno diverse applicazioni e spaziano in diversi campi. In questo paragrafo elencherò alcune applicazioni interessanti che ho trovato sulla rete e poi mostrerò come è possibile creare un molto rudimentale sistema di riconoscimento dii  immagini, capace di riconoscere i numeri da 0 a 9.</p>
<p><span id="more-345"></span></p>
<p align="justify">Alcune applicazioni sono:</p>
<p align="justify">Vita artificiale: la vita artificiale tenta di simulare l&#8217;evoluzione di organismi viventi tramite computer. Spesso gli organismi sono dotati di reti neurali per svolgere i loro compiti come trovare fonti di cibo, muoversi, etc&#8230;</p>
<p align="justify">Finanza: prevedere l&#8217;andamento dei mercati.</p>
<p align="justify">Riconoscimento di forme, immagini, facce, etc&#8230;</p>
<p align="justify">Quello che noi creeremo è un sistema molto rudimentale di riconoscimento delle immagini, di fatto potra riconoscere solo quelle immagini che gli abbiamo presentato nel training set e non sarà probabilmente in grado di riconoscerle se gli è stato modificato anche solamente qualche pixel. E&#8217; solo un esempio di base per mostrare cosa si può fare, ed anche in maniera abbastanza semplice. Le immagini che la nostra rete neurale sarà capace di riconoscere avranno dimensioni fisse (5&#215;7 pixels) e saranno simili a questa:</p>
<div id="attachment_346" class="wp-caption aligncenter" style="width: 108px"><a href="http://mindunpacked.com/wp-content/uploads/2008/12/1.png"><img class="size-medium wp-image-346" title="1" src="http://mindunpacked.com/wp-content/uploads/2008/12/1.png" alt="Immagine di esempio" width="98" height="138" /></a><p class="wp-caption-text">Immagine di esempio</p></div>
<p align="justify">
<p align="justify">
<p align="justify">
<p align="justify">I quadratini con il bordo nero sono semplicemente i pixel dell&#8217;immagine. Avendo questa immagine 7&#215;5 = 35 pixel in totale, la nostra rete neurale dovrà avere 35 neuroni di input, uno per ogni pixel. Per semplicità l&#8217;input potrà essere o 1 o 0, dove 1 simboleggia il colore rosso della precedente immagine e 0 lo sfondo. Così facendo si ottiene una matrice che rappresenta l&#8217;immagine, che nel caso di quella appena vista sarebbe questa:</p>
<p align="justify">
<p align="center">0 0 1 0 0</p>
<p align="center">0 1 1 0 0</p>
<p align="center">0 0 1 0 0</p>
<p align="center">0 0 1 0 0</p>
<p align="center">0 0 1 0 0</p>
<p align="center">0 0 1 0 0</p>
<p align="center">0 1 1 1 0</p>
<p align="center">
<p align="justify">Nell&#8217;allenamento della nostra rete, noi daremo un solo esempio per ogni numero, ma volendo potremmo dare più esempi diversi che rappresentano diversi modi di scrivere il numero 1 e così la nostra rete avrebbe una capacità più alta di riconoscere caratteri diversi (chiaramente l&#8217;allenamento sarà più lungo).</p>
<p align="justify">Per la nostra rete neurale creeremo noi il training set direttamente su un file di testo o altrimenti, essendo la rete neurale capace di riceve in input solo dei numeri, dovremmo creare un programma che data in input un&#8217;immagine crei la matrice numerica associata ad essa, ma siccome il nostro training set sarà molto piccolo le creeremo manualmente. Ogni riga dovrà contenere la rappresentazione di un numero, di conseguenza non avremo matrici nel file di input ma le righe saranno affiancate. Il file di input risulta così:</p>
<p align="justify">
<p style="text-align: center;">0 0 1 0 0 0 1 0 1 0 0 1 0 1 0 0 1 0 1 0 0 1 0 1 0 0 1 0 1 0 0 0 1 0 0</p>
<p style="text-align: center;">0 0 1 0 0 0 1 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 1 1 0</p>
<p style="text-align: center;">0 0 1 1 0 0 1 0 0 1 0 1 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 1 1 1 1</p>
<p style="text-align: center;">0 0 1 1 0 0 1 0 0 1 0 1 0 0 1 0 0 0 1 0 0 0 0 0 1 0 1 0 0 1 0 0 1 1 0</p>
<p style="text-align: center;">0 0 0 0 0 0 0 0 1 0 0 0 1 1 0 0 1 0 1 0 1 1 1 1 1 0 0 0 1 0 0 0 0 1 0</p>
<p style="text-align: center;">0 1 1 1 0 0 1 0 0 0 0 1 0 0 0 0 1 1 1 0 0 0 0 0 1 0 0 0 0 1 0 1 1 1 0</p>
<p style="text-align: center;">0 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 1 1 0 1 0 0 0 1 1 0 0 0 1 0 1 1 1 0</p>
<p style="text-align: center;">0 0 0 0 0 1 1 1 1 1 0 0 0 0 1 0 0 0 1 0 0 1 1 1 0 0 1 0 0 0 1 0 0 0 0</p>
<p style="text-align: center;">0 1 1 1 0 1 0 0 0 1 1 0 0 0 1 0 1 1 1 0 1 0 0 0 1 1 0 0 0 1 0 1 1 1 0</p>
<p style="text-align: center;">0 1 1 1 0 1 0 0 0 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 0</p>
<p style="text-align: center;">
<p align="justify">Se spezzate ogni riga in parti composte da 5 elementi riottenete la matrice che rapresenta il numero.</p>
<p align="justify">Il file di output avrà tante righe quante quelle del file di input e sarà il seguente:</p>
<p align="justify">
<p style="text-align: center;">1 0 0 0 0 0 0 0 0 0</p>
<p style="text-align: center;">0 1 0 0 0 0 0 0 0 0</p>
<p style="text-align: center;">0 0 1 0 0 0 0 0 0 0</p>
<p style="text-align: center;">0 0 0 1 0 0 0 0 0 0</p>
<p style="text-align: center;">0 0 0 0 1 0 0 0 0 0</p>
<p style="text-align: center;">0 0 0 0 0 1 0 0 0 0</p>
<p style="text-align: center;">0 0 0 0 0 0 1 0 0 0</p>
<p style="text-align: center;">0 0 0 0 0 0 0 1 0 0</p>
<p style="text-align: center;">0 0 0 0 0 0 0 0 1 0</p>
<p style="text-align: center;">0 0 0 0 0 0 0 0 0 1</p>
<p><center><script type="text/javascript">
heyos_ad_user = 11334;
heyos_ad_type = "G";
heyos_ad_format = "1";
heyos_color_border = "23292b";
heyos_color_bg = "23292b";
heyos_color_link = "FFFFFF";
heyos_color_text = "21b8ca";
heyos_color_url = "21b8ca";
</script>
<script type="text/javascript" src="http://admaster.heyos.com/core/bnr.js"></script></center></p>
<p align="justify">I neuroni di output saranno 10 ed ognuno è associato ad un numero. Con il numero 0 il primo neurone emette un segnale mentre gli altri no, con il numero 1 il secondo neurone emette un segnale mentre gli altri no, etc&#8230; di conseguenza ci aspettiamo che dopo l&#8217;addestramento, quando passiamo in input, per esempio il numero 9 soltanto l&#8217;ultimo neurone si attiverà. Il codice è il seguente:</p>
<pre class="brush: cpp;">
#include &lt;iostream&gt;
#include &lt;fstream&gt;
#include &lt;sstream&gt;
#include &lt;vector&gt;
#include &lt;ctime&gt;
#include &lt;cmath&gt;

using namespace std;

#include &quot;Misc.hpp
#include &quot;GenAlg.hpp&quot;
#include &quot;NeuralNet.hpp&quot;
#include &quot;NNController.hpp&quot;

int main() {
NNController NC(35, 10, 1, 10);
NC.loadTrainingSet(&quot;input&quot;, &quot;output&quot;);
NC.train();
NC.saveWeights(&quot;img.txt&quot;);
cout &lt;&lt; &quot;*** La rete e' allenata ***&quot; &lt;&lt; endl;
}
</pre>
<p align="justify">Come vedete, abbiamo creato 35 neuroni di input, 10 di output ed un livello nacosto con 10 neuroni.</p>
<p align="center"><strong>LINKS</strong></p>
<p align="justify"><a href="http://www.ai-junkie.com/ann/evolved/nnt1.html">http://www.ai-junkie.com/ann/evolved/nnt1.html</a> &#8211; Questo tutorial in Inglese sulle reti neurali è uno dei migliori che abbia mai letto, tant&#8217;è che ne ho preso spunto per scrivere questo. Vengono usati anche lì gli algoritmi genetici per aggiornare la rete e troverete delle somiglianze anche nelle classi del codice (però vi assicuro che il codice per questo tutorial l&#8217;ho scritto da zero <img src='http://mindunpacked.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><a href="http://www.ai-junkie.com/ga/intro/gat1.html">http://www.ai-junkie.com/ga/intro/gat1.html</a> &#8211; Tutorial sugli algoritmi genetici, sempre in Inglese.</p>
<p><a href="http://blacklight.gotdns.org/wiki/index.php/Introduzione_ai_sistemi_fuzzy_e_alle_reti_neurali">http://blacklight.gotdns.org/wiki/index.php/Introduzione_ai_sistemi_fuzzy_e_alle_reti_neurali</a> &#8211; Implementazione di una rete neurale error back propagation in C, tutorial in Italiano.</p>
<p align="justify"><a href="http://www.aitalk.net/">http://www.aitalk.net</a> &#8211; Forum sull&#8217;intelligenza artificiale in lingua Inglese. Contiene anche una piccola sezione in lingua Italiana.</p>
<p>Ho anche realizzato la stessa guida in formato PDF: trovate <a href="http://www.mindunpacked.com/risorse/TutorialRetiNeurali.tar.gz">QUI</a> un archivio contenente tutti i file sorgente di cui abbiamo parlato e la guida in formato PDF (un po meglio impaginata e con qualche illustrazione in piu&#8217;).<br />
Alla prossi</p>
]]></content:encoded>
			<wfw:commentRss>http://mindunpacked.com/2008/reti-neurali-attraverso-algoritmi-genetici-in-c-parte-vi-ultima/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Steganografia in C++</title>
		<link>http://mindunpacked.com/2008/steganografia-in-c/</link>
		<comments>http://mindunpacked.com/2008/steganografia-in-c/#comments</comments>
		<pubDate>Sun, 28 Dec 2008 19:13:21 +0000</pubDate>
		<dc:creator>Francesco</dc:creator>
				<category><![CDATA[Informatica]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[LSB]]></category>
		<category><![CDATA[Steganografia]]></category>

		<guid isPermaLink="false">http://mindunpacked.com/?p=321</guid>
		<description><![CDATA[Su Mind Unpacked abbiamo gia&#8217; parlato di steganografia digitale in due precedenti articoli (Introduzione alla steganografia digitale e Algoritmi steganografici), oggi percio&#8217; discuteremo di un&#8217;implementazione in C++ dell&#8217;algoritmo LSB. L&#8217;algoritmo e&#8217; gia&#8217; stato trattato dal punto di vista teorico nei precedenti articoli, quindi non mi soffermero&#8217; piu&#8217; di tanto su di esso e passero&#8217; quasi [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify">Su Mind Unpacked abbiamo gia&#8217; parlato di <strong>steganografia</strong> digitale in due precedenti articoli (<a title="Introduzione alla steganografia digitale" href="http://mindunpacked.com/2008/introduzione-alla-steganografia-digitale/" target="_blank">Introduzione alla steganografia digitale</a> e <a title="Algoritmi steganografici" href="http://mindunpacked.com/2008/algoritmi-steganografici/" target="_blank">Algoritmi steganografici</a>), oggi percio&#8217; discuteremo di un&#8217;<strong>implementazione in C++ dell&#8217;algoritmo LSB</strong>. L&#8217;algoritmo e&#8217; gia&#8217; stato trattato dal punto di vista teorico nei precedenti articoli, quindi non mi soffermero&#8217; piu&#8217; di tanto su di esso e passero&#8217; quasi subito alla spiegazione del codice.</p>
<p><span id="more-321"></span></p>
<p style="text-align: justify">L&#8217;algoritmo <strong>LSB</strong> (least significat bit) mira a nascondere un messaggio in un contenitore (immagine, file audiom file video) modificando i bit meno significativi. Nel nostro caso creeremo un programma per <strong>nascondere file di testo all&#8217;interno di immagin</strong><strong>i</strong> bitmap. Ogni pixel della nostra immagine e&#8217; rappresentato da una terna di numeri che indicano le tre componenti RGB. Modificheremo il bit meno significativo di ogni componente di ogni pixel e lo adatteremo ai bit del nostro messaggio di testo. Il cambiamento che otteremo modificando solo il bit meno significativo sara&#8217; al massimo di una unita&#8217; e, di conseguenza, produrra&#8217; immagini all&#8217;apparenza identiche, poiche&#8217; un tale cambiamento non e&#8217; percepibile ad occhio nudo.</p>
<p style="text-align: justify">Il nostro programma e&#8217; sostanzialmente diviso in due parti: quella per nascondere il testo nell&#8217;immagine e quella per recuperarlo.</p>
<p style="text-align: justify"><strong>Steganografare un testo</strong></p>
<p style="text-align: justify">La prima parte del programma si occupera&#8217; di fare le seguenti operazioni:</p>
<ol>
<li style="text-align: justify">Leggere il messaggio da un file di testo</li>
<li>Calcolare il numero di pixels necessari ad occultare il messaggio nell&#8217;immagine ed accertarsi che l&#8217;immagine sia abbastanza grande da poterlo fare. Salvare in forma binaria il valore di ogni componente di questi pixels.</li>
<li>Modificare i bit meno significativi per adattarli a quelli del messaggio</li>
<li>Scrivere i nuovi bit su una nuova immagine apparentemente uguale alla prima, ma contenente il testo.</li>
</ol>
<p>Saltando il passo 1 (che spero chiunque sia capace di fare), passiamo al due:</p>
<pre class="brush: cpp;">
numbits = message.size()*8;  // La stringa message contiene il messaggio letto dal file
numpixels = (numbits%3 == 0 ? numbits/3 : (int)numbits/3 + 1);
numrows = (int)numpixels/img.TellWidth() + 1;
if (numrows &gt; img.TellHeight()) {
	cout &lt;&lt; &quot;Errore: il messaggio e' troppo lungo per essere contenuto in questa immagine.&quot; &lt;&lt; endl;
	exit(0);
}
for (int i = 0; i &lt; numrows; i++) {
	for (int j = 0; j &lt; img.TellWidth(); j++) {
		bits.push_back(bitset&lt;8&gt;((int)img(j, i)-&gt;Red));
		bits.push_back(bitset&lt;8&gt;((int)img(j, i)-&gt;Green));
		bits.push_back(bitset&lt;8&gt;((int)img(j, i)-&gt;Blue));
	}
}
</pre>
<p><!--adsense--></p>
<p>Il programma calcola il numero di bit e il numero di pixel necessari in base alla lunghezza del messaggio. Visto che ogni pixel puo&#8217; nascondere 3 bit, il numero di pixel viene calcolato semplicemente dividendo il numero di bit per 3 e arrotondando per eccesso nel caso di resto. numrows contiene invece il numero di righe dell&#8217;immagine che bisogna copiare in memoria. Se il numero di righe e&#8217; maggiore dell&#8217;altezza del&#8217;immagine il programma genera un errore poiche&#8217; l&#8217;immagine e&#8217; troppo piccola per contenere il messaggio. Dopo aver fatto cio&#8217;, salviamo i tutti i valori RGB dei pixel che ci servono in un array di bitset. bits e&#8217; un vettore (classe vector delle STL) di oggetti bitset, una classe della STL creata appositamente per gestire dati in forma binaria. La notazione bitset&lt;8&gt;(&#8230;) crea un oggetto bitset con 8 bit che assumono il valore dell&#8217;argomento che gli si passa tra parentesi. Visto che i valori RGB di un&#8217;immagine sono compresi tra 0 e 255 8 bit sono sufficienti.</p>
<pre class="brush: cpp;">
count = 0;
for (int i = 0; i &lt; message.size(); i++) {
	bitset&lt;8&gt; temp = bitset&lt;8&gt;(message[i]);
	for (int b = 7; b &gt;= 0; b--) {
		bits[count].set(0, temp[b]); // 0 e' l'indice del bit meno significativo; 		temp[b] e' il b-esimo bit della lettera che stiamo esaminando
		count++;
	}
}
</pre>
<p>Dopo aver salvato i valori in memoria, dobbiamo modificare il bit meno significativo di ogni elemento salvato per renderlo uguale a quello del nostro messaggio. Il codice qui sopra svolge questo compito: scorre ogni lettera del messaggio e crea un oggetto bitset contenente il valore di quella lettera in binario. Il ciclo innestato scorre tutti i bit della lettera e modifica i bit meno significativi dell&#8217;immagine in modo appropriato.</p>
<pre class="brush: cpp;">
for (int i = 0; i &lt; numrows; i++) {
	for (int j = 0; j &lt; img.TellWidth(); j++) {
		imgout(j, i)-&gt;Red = (int)bits[count++].to_ulong();
		imgout(j, i)-&gt;Green = (int)bits[count++].to_ulong();
		imgout(j, i)-&gt;Blue = (int)bits[count++].to_ulong();
	}
}
for (int i = numrows; i &lt; img.TellHeight(); i++) {
	for (int j = 0; j &lt; img.TellWidth(); j++) {
		imgout(j, i)-&gt;Red = img(j, i)-&gt;Red;
		imgout(j, i)-&gt;Green = img(j, i)-&gt;Green;
		imgout(j, i)-&gt;Blue = img(j, i)-&gt;Blue;
	}
}
imgout.WriteToFile(&quot;out.bmp&quot;);
</pre>
<p><!--adsense--></p>
<p>Una volta che i bit sono stati modificati in maniera corretta, dobbiamo solo riscriverli su una nuova immagine. Il primo ciclo scrive i bit contenenti il messaggio (la funzione to_ulong() converte un bitset nel suo valore decimale), mentre il secondo riscrive semplicemente i valori dei pixel che non sono stati modificati riprendendoli dall&#8217;immagine originale.</p>
<p><strong>Recuperare il testo steganografato</strong></p>
<p>La seconda parte del programma e&#8217; quella che, data in input un&#8217;immagine recupera il testo contenuto in essa. Un difetto del programma e&#8217; quello di richiedere la lunghezza del messaggio per poterlo estrarre: in realta&#8217; si potrebbe ovviare a questo problema in maniera piuttosto semplice (dopo vedremo come) ma per ora, bisognera&#8217; accontentarsi di andare a tentativi se non si conosce la lunghezza del messaggio completo.</p>
<p>La struttura di questa seconda parte ricalca quella della prima: dopo aver preso in input la lunghezza del messaggio ed aver calcolato in base ad essa il numero di pixel che sono stati modificati, il programma prende dall&#8217;immagine i valori delle componenti di questi pixel e li mette in un array di bitset. Un secondo ciclo:</p>
<pre class="brush: cpp;">
for (int i = 1; i &lt; numbits; i++) {
	temp.set(count, bits[i-1][0]);
	count--;
	if (count == -1) {
		count = 7;
		cout &lt;&lt; (char)temp.to_ulong();
	}
}
</pre>
<p>si occupa di prendere i bit meno significativi a gruppi di 8 e di stampare il corrispondente valore alfanumerico.</p>
<p><strong>Possibili miglioramenti</strong></p>
<p>Il programma in questa maniera e&#8217; piuttosto rudimentale, ecco alcuni possibili miglioramenti che potreste allenarvi a mettere in pratica:</p>
<ol>
<li>Evitare di dover richiedere la lunghezza quando bisogna estrarre un messaggio. Una possibilita&#8217; potrebbe essere quella di conservare i primi N bit meno significativi dell&#8217;immagine per salvare la lunghezza del messaggio e per estrarla al volo senza doverla richiedere all&#8217;utente. 10 bit permetterebbero, per esempio, di salvare un numero fino a 2<sup>10</sup> = 1024.</li>
<li>Introdurre la possibilita&#8217; di inserire una chiave. Una chiave potrebbe essere un numero intero N che indicherebbe al programma di modificare non tutti i pixel uno per uno ma di prendere 1 pixel ogni N. Questo ridurrebbe la capacita&#8217; dell&#8217;immagine di contenere messaggi ma renderebbe piu&#8217; difficile un&#8217;eventuale individuazione del messaggio.</li>
<li>Introdurre la possibilita&#8217; di crittografare un messaggio prima di steganografarlo per una maggiore sicurezza.</li>
</ol>
<p>Ecco il codice del programma: <a href="../../risorse/Stego.zip">Steganografia in C++</a>. Fa uso delle librerie EasyBMP per la gestione delle immagini presenti nell&#8217;archivio stesso.</p>
<p>Ciao!</p>
]]></content:encoded>
			<wfw:commentRss>http://mindunpacked.com/2008/steganografia-in-c/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Animare il Buddhabrot</title>
		<link>http://mindunpacked.com/2008/animare-il-buddhabrot/</link>
		<comments>http://mindunpacked.com/2008/animare-il-buddhabrot/#comments</comments>
		<pubDate>Wed, 17 Dec 2008 16:55:53 +0000</pubDate>
		<dc:creator>Francesco</dc:creator>
				<category><![CDATA[Informatica]]></category>
		<category><![CDATA[Buddhabrot]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[Frattali]]></category>

		<guid isPermaLink="false">http://mindunpacked.com/?p=244</guid>
		<description><![CDATA[In un precedente articolo abbiamo visto come sia possibile renderizzare immagini dell&#8217;insieme di Mandelbrot ottenendo il cosiddetto Buddhabrot. Oggi mostrerò come si possano renderizzare, invece, delle animazioni del Buddhabrot sfruttando il fatto che questo frattale puo&#8217; essere &#8220;interpretato&#8221; come un oggetto in quattro dimensioni. Spiegare cio&#8217; non e&#8217; molto facile, per il semplice motivo che [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify;">In un <a title="Renderizzare il Buddhabrot" href="http://mindunpacked.com/2008/un-nuovo-metodo-per-visualizzare-linsieme-di-mandelbrot-il-buddhabrot/" target="_self">precedente articolo</a> abbiamo visto come sia possibile renderizzare immagini dell&#8217;insieme di Mandelbrot ottenendo il cosiddetto <strong>Buddhabrot</strong>. Oggi mostrerò come si possano renderizzare, invece, delle <strong>animazioni del Buddhabrot</strong> sfruttando il fatto che questo frattale puo&#8217; essere &#8220;interpretato&#8221; come un oggetto in quattro dimensioni. Spiegare cio&#8217; non e&#8217; molto facile, per il semplice motivo che non ci e&#8217; possibile visualizzare un oggetto in 4 dimensioni e che dobbiamo accontentarci di una approssimazione creata dalla nostra immaginazione, ma faro&#8217; del mio meglio per rendere l&#8217;articolo il piu&#8217; chiaro possibile.<br />
<span id="more-244"></span><br />
Il concetto di base e&#8217; questo: quando utilizziamo la formula di Mandelbrot e cioe&#8217; Z<sub>n+1</sub>=Z<sub>n</sub><sup>2</sup> + C i valori che entrano in gioco sono 4 e sono le parti reali di Z e C e le loro parti immaginarie (d&#8217;ora in poi saranno indicate con Z.r, C.r, Z.i, C.i); per ogni possibile combinazione di questi quattro valori avremo un solo valore in uscita, diverso per ogni combinazione. Visto pero&#8217;, che non possiamo visualizzare un oggetto in quattro dimensioni, l&#8217;unica cosa che possiamo fare e&#8217; visualizzare una sezione bidimensionale dell&#8217;oggetto, ed e&#8217; questo quello che accade quando poniamo Z=0 nel renderizzare l&#8217;insieme di Mandelbrot. Gli insieme di Julia non sono altro che sezioni dello stesso oggetto ma su piani diversi (che corrispondono ad una diversa scelta del valore iniziale di Z).</p>
<p style="text-align: justify;">In un ambiente tridimensionale abbiamo 3 piani perpendicolari tra di loro; in <strong>4 dimensioni</strong> invece, questi piani diventano 6 e sono rappresentati appunto dalle varie coppie possibili dei 4 valori in entrata: [Z.r, Z.i], [Z.r, C.r], [Z.r, C.i], [Z.i, C.r], [Z.i, C.i], [C.r, C.i]. Questi piani sono tutti perpendicolari tra di loro e sono i piani che si riconoscono a prima vista, ma ovviamente il numero di piani su cui potremmo effettuare delle sezioni da visualizzare e&#8217; infinito. Questo e&#8217; il punto che ci permette di renderizzare delle vere e proprie animazioni che includono delle <strong>rotazioni del Buddhabrot</strong>. Prima di parlare di questo, pero&#8217;, vediamo quali sono le modifiche da effettuare al file sorgente che ho distribuito nel precedente articolo per renderizzare sezioni di piani diverse.</p>
<p style="text-align: justify;">In realta&#8217;, la modifica da fare e&#8217; una sola ed e&#8217; questa: nella funzione escape() si trova questa parte:</p>
<pre class="brush: cpp;">
zz[(int)N].r = ZOOM*(Z.r+OFFSET_X)*(WIDTH/2);
zz[(int)N].i = ZOOM*(Z.i)*(HEIGHT/2) + HEIGHT/2;
</pre>
<p style="text-align: justify;">Come vedete, le coordinate che prendiamo in considerazione sono Z.r e Z.i. Basta cambiare questi valori per renderizzare un&#8217;altra sezione del frattale. Se al posto di Z.i mettiamo, per esempio, C.r, visualizzeremo l&#8217;oggetto visto dal piano [Z.r, C.r].</p>
<p style="text-align: justify;">Vediamo ora come realizzare una rotazione del frattale. Quello che vogliamo fare e&#8217;, in poche parole, passare gradualmente dall&#8217;immagine di un piano, diciamo [Z.r, Z.i] a quella di un&#8217;altro, per esempio, [Z.i, C.r]. Per fare cio&#8217; dobbiamo modificare sempre la formula precedente, nella seguente maniera:</p>
<pre class="brush: cpp;">
zz[(int)N].r = ZOOM*(rot*Z.r+Z.i*(1-rot)+OFFSET_X)*(WIDTH/2);
zz[(int)N].i = ZOOM*(rot*Z.i+C.r*(1-rot))*(HEIGHT/2) + HEIGHT/2;
</pre>
<p><!--adsense--></p>
<p style="text-align: justify">E&#8217; apparso un nuovo coefficiente, rot. Questo, come potete immaginare, e&#8217; un coefficiente che rappresenta, se vogliamo, l&#8217;angolo di rotazione. Per un valore di rot pari a 1, verra&#8217; renderizzato il piano [Z.r, Z.i] poiche&#8217; 1-rot = 0 e quindi le parti Z.i e C.r si annullano. Per rot = 0, avverra&#8217; il contrario. Ovviamente per valori di rot che variano tra 0 e 1 otteremo immagini diverse, per esempio, visto che la rotazione complessiva e&#8217; di 90° (da rot = 0 a rot = 1), rot=0.5 dovrebbe corrispondere ad una rotazione di 45°. Se si renderizzano varie immagini per valori di rot che aumentano progressivamente da 0 a 1, si otterra&#8217; una vera e propria animazione del Buddhabrot rotante.</p>
<p style="text-align: justify">Ora, se non volete mettervi a modificare manualmente ogni volta il valore di rot, vi conviene aggiungere un paio di cicli for al codice e fare in modo che, ad ogni ciclo, il valore di rot venga modificato per renderizzare un&#8217;immagine diversa. Ecco un esempio di &#8220;rotazione&#8221;, anche se non appare affatto come tale:</p>
<p style="text-align: center"><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="425" height="344" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube.com/v/NcyQHsuv-1o&amp;hl=it&amp;fs=1" /><embed type="application/x-shockwave-flash" width="425" height="344" src="http://www.youtube.com/v/NcyQHsuv-1o&amp;hl=it&amp;fs=1" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<p style="text-align: justify">Vi lascio un ultimo link alla pagina originale creata da chi ha scoperto questa tecnica (e&#8217; in inglese): <a title="Buddhabrot Hologram" href="http://www.superliminal.com/fractals/bgram/ZrZiOut.htm" target="_blank">http://www.superliminal.com/fractals/bgram/ZrZiOut.htm</a></p>
]]></content:encoded>
			<wfw:commentRss>http://mindunpacked.com/2008/animare-il-buddhabrot/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Reti neurali attraverso algoritmi genetici in C++. Parte V</title>
		<link>http://mindunpacked.com/2008/reti-neurali-attraverso-algoritmi-genetici-in-c-parte-v/</link>
		<comments>http://mindunpacked.com/2008/reti-neurali-attraverso-algoritmi-genetici-in-c-parte-v/#comments</comments>
		<pubDate>Fri, 12 Dec 2008 13:07:07 +0000</pubDate>
		<dc:creator>Francesco</dc:creator>
				<category><![CDATA[Informatica]]></category>
		<category><![CDATA[Algoritmi genetici]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[Intelligenza artificiale]]></category>
		<category><![CDATA[Reti neurali]]></category>

		<guid isPermaLink="false">http://mindunpacked.com/?p=252</guid>
		<description><![CDATA[In questa penultima parte della serie di articoli dedicati alle reti neurali, vedremo come creare una classe che riunisca tutto cio&#8217; che abbiamo programmato in precedenza e ne renda piu&#8217; facile l&#8217;utilizzo. Era gia&#8217; possibile utilizzare le classi cosi&#8217; com&#8217;erano, ma in questo modo ci rendiamo la vita piu&#8217; semplice. Inoltre c&#8217;e&#8217; da notare che [...]]]></description>
			<content:encoded><![CDATA[<p>In questa penultima parte della serie di articoli dedicati alle reti neurali, vedremo come creare una classe che riunisca tutto cio&#8217; che abbiamo programmato in precedenza e ne renda piu&#8217; facile l&#8217;utilizzo. Era gia&#8217; possibile utilizzare le classi cosi&#8217; com&#8217;erano, ma in questo modo ci rendiamo la vita piu&#8217; semplice. Inoltre c&#8217;e&#8217; da notare che quello che faremo oramai non ho molto a che fare con l&#8217;implementazione della rete, ma e&#8217; piu&#8217; una questione di ordine e OOP.</p>
<p><span id="more-252"></span></p>
<p align="center"><strong>Riunire il tutto.</strong></p>
<p align="justify">In questo piccolo paragrafo vedremo come fare comunicare tra loro le due classi attraverso una terza ed ultima classe che si occupa della gestione di tutte le operazioni. In realtà questa classe è superflua perchè è già possibile, con le sole classi Population e NeuralNet, creare una rete neurale funzionante ma essa ci rende molto più comoda la scritture del codice. Essa contiene per lo più funzioni ausiliarie come quella per caricare il training set (senza dover parsare manualmente il file), o per salvare e caricare i pesi della rete neurale e per questo non mi soffermerò molto sul codice. La funzione più importante è quella che esegue l&#8217;allenamento della rete neurale, ma vediamo prima il codice della classe:</p>
<pre class="brush: cpp;">
class NNController {
	public:
		NNController(int c_numInputNeurons, int c_numOutputNeurons,
		int c_numHiddenLayers, int c_numNeuronsPerLayer);
		void loadTrainingSet(string inputFile, string outputFile);
		void train();
		void saveWeights(string file);
		void loadWeights(string file);
		void test();
	private:
		vector&lt; vector &gt; inputData; // Training set
		vector&lt; vector &gt; outputData;
		NeuralNet* N;
		Population* P;
		Chromosome* C;
};
</pre>
<p align="justify">Il costruttore ha gli stessi parametri di quello della classe NeuralNet che servono ad inizializzare l&#8217;oggetto N all&#8217;interno di questa classe.</p>
<p align="justify">La funzione loadTrainingSet(string inputFile string outputFile) carica appunto il training set: essa riceve come argomenti i nomi di due file, il primo deve contenere gli input da passare alla rete neurale mentre il secondo gli output desiderati corrispondenti agli input. Per esempio, se stiamo addestrando la rete a fare la somma di due numeri, ed il file contenente l&#8217;input contenesse:</p>
<p align="justify">
<p align="justify">0 1</p>
<p align="justify">0 2</p>
<p align="justify">
<p align="justify">Quello contenente l&#8217;output dovrebbe contenere:</p>
<p align="justify">1</p>
<p align="justify">2</p>
<p align="justify">(Gli input devono essere separati tra di loro da uno spazio ed ogni riga deve contenere ovviamente sempre lo stesso numero di input che deve essere a sua volta uguale al numero dei neuroni di input specificato nel codice).</p>
<p align="justify">Le funzioni saveWeights(string file) e loadWeights(string file) servono rispettivamente a salvare i pesi della rete neurale (generalmente dopo che questa è allenata) e a poterli caricare in seguito senza dover ripetere l&#8217;addestramento.</p>
<p align="justify">La funzione test() serve invece a poter testare la rete con vari input dopo che questa è stata allenata. Ho conservato volutamente alla fine la funzione train() perchè è l&#8217;unica un po più complessa e serve ad effettuare l&#8217;allenamento della rete.</p>
<pre class="brush: cpp;">
void NNController::train() {
	double currentErr = 0; int i = 0; double bestFit = 99999999;&lt;
	while (bestFit &gt; MAX_ERROR) {
		if (i &gt;= MAX_EPOCHS) {
			break;
		}
		for (int j = 0; j &lt; POPULATION_SIZE; j++) {
			currentErr = 0;
			for (int k = 0; k &lt; inputData.size(); k++) {
				N-&gt;run(inputData[k], (*P)[j]);
				currentErr += N-&gt;globalError(outputData[k]) / inputData.size()
			}
			(*P)[j]-&gt;setFitness(currentErr);
		}
		bestFit = P-&gt;best()-&gt;getFitness();
		if (i % UPDATE == 0) {
			cout &lt;&lt; &quot;(&quot; &lt;&lt; i &lt;&lt; &quot;) - &quot;&lt;&lt; &quot;Best = &quot; &lt;&lt; bestFit
			     &lt;&lt; &quot;\t&quot; &lt;&lt; &quot;Worst = &quot; &lt;&lt; P-&gt;worst()-&gt;getFitness()
			     &lt;&lt; endl;
		}
		P-&gt;next();
		i++;
	}
}
</pre>
<p><!--adsense--></p>
<p align="justify">La funzione esegue un ciclo while che termina o quando il fitness raggiunge un livello accettabile (cioè l&#8217;errore raggiunto è minore o uguale all&#8217;errore massimo stabilito in precedenza e definito nella costante MAX_ERROR) oppure quando (vedete il break) il numero di epoche (cioè di cicli di riproduzione della popolazione) supera un certo limite. Dentro questo ciclo while c&#8217;è un ulteriore ciclo for che scorre tutti gli elementi della popolazione (che, come oramai dovrebbe essere chiaro, rappresenta una configurazione dei pesi della rete neurale) e per ognuno esegue tutto il training set in input. Il fitness di questo individuo sarà l&#8217;errore medio che il cromosoma ha sugli elementi del training set. Un errore pari a 0, che corrisponde alla perfezione assoluta, è praticamente impossibile da raggiungere e quindi, a seconda dei casi, ci si può accontentare di un errore più o meno alto come, per esempio, 0.001.</p>
<p align="justify">La funzione stampa anche un output ogni tanto per informare l&#8217;utente a che punto è arrivato l&#8217;allenamento, e dipende dal valore della costante UPDATE: se per esempio questa vale 50, ogni 50 generazioni sarà stampato un messaggio contente i fitness del migliore e del peggiore cromosoma della popolazione corrente.</p>
<p align="justify">Quando questa funzione termina la nostra rete neurale è allenata (con un errore massimo stabilito dalla costante MAX_ERROR) ed è possibile testarla tramite il metodo test() fornito dalla stessa classe.</p>
<p align="justify">Vediamo ora un codice di esempio di rete neurale realizzata con le nostre classi:</p>
<pre class="brush: cpp;">
#include &lt;iostream&gt;
#include &lt;fstream&gt;
#include &lt;sstream&gt;
#include &lt;vector&gt;
#include &lt;ctime&gt;
#include &lt;cmath&gt;

using namespace std;

/* Misc.hpp è un header che contiene le varie costanti come
MAX_POPULATION, ELITISM, MAX_TOUR, etc...
Gli altri header contengono le varie classi */
#include &quot;Misc.hpp&quot;
#include &quot;GenAlg.hpp&quot;
#include &quot;NeuralNet.hpp&quot;
#include &quot;NNController.hpp&quot;

int main() {
	/* Alla riga seguente creiamo una rete neurale con 2 neuroni
	di input, 1 neurone di output e 0 layer nascosti */
	NNController NC(2, 1, 0, 0);
	/* Carica il training set contenuto nei due file */
	NC.loadTrainingSet(&quot;input&quot;, &quot;output&quot;);
	NC.train();
	cout &lt;&lt; &quot;*** La rete e' allenata ***&quot; &lt;&lt; endl;
	NC.test();
}
</pre>
<p align="justify">Come vedete il codice è davvero basilare eppure una rete neurale come quella di questo esempio, sarebbe in grado di imparare a fare la somma di due numeri con soli tre neuroni!</p>
<p align="center"><strong>Come impostare una rete neurale.</strong></p>
<p align="justify">Abbiamo visto la creazione pratica di una rete neurale ma come avete notato il risultato ottenuto da una rete dipende da una miriade di fattori come per esempio il numero di livelli, il numero di neuroni presente nei livelli nascosti, la funzione di trasferimento, etc&#8230; di conseguenza vi starete probabilmente chiedendo quali sono le impostazioni migliori per una rete neurale. Chiaramente non esistono delle impostazioni migliori in assoluto, ma dipende tutto dal problema che dobbiamo analizzare, di conseguenza quelle che scriverò qui saranno solo delle brevi linee guida da tenere in considerazione ma non delle regole fisse.</p>
<p align="justify">Ho gia parlato in precedenza delle funzioni di attivazione e di quali sia più comodo usare a seconda dei casi, ora parleremo del numero dei livelli.</p>
<p align="justify">Quanti livelli nascosti vanno usati? Nell&#8217;esempio precedente abbiamo creato una rete capace di imparare a fare la somma dei due numeri senza utilizzare nessun livello nascosto e in molti casi può verificarsi questa eventualità. Generalmente, nei casi restanti, un solo livello nascosto è più che sufficiente per ottenere risultati corretti. Dal punto di vista matematico possiamo dire che una rete neurale con i soli livelli si input e outputè capace di risolvere problemi linearmente separabili, mentre per problemi non linearmente separabili sono richiesti uno o più livelli nascosti.</p>
<p align="justify">Il numero di neuroni per ogni livello nascosto può essere un&#8217;altra incognita nella creazione della rete neurale: esso dipende da più fattori come il numero dei neuroni di input e di output, la dimensione del training set, la funzione di attivazione, l&#8217;algoritmo di apprendimento, etc&#8230; Esistono diverse regole approssimative che cercano di fornire un modo per calcolare il numero di unità nascoste necessarie (per esempio: &#8220;il numero di unità nascoste deve essere sempre minore del doppio dei neuroni di input&#8221;) ma molto spesso esse sono inutili. La cosa migliore è fare alcune prove e trovare il numero di unità che fornisce un errore minimo.</p>
]]></content:encoded>
			<wfw:commentRss>http://mindunpacked.com/2008/reti-neurali-attraverso-algoritmi-genetici-in-c-parte-v/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Reti neurali attraverso algoritmi genetici in C++. Parte III</title>
		<link>http://mindunpacked.com/2008/reti-neurali-attraverso-algoritmi-genetici-in-c-parte-iii/</link>
		<comments>http://mindunpacked.com/2008/reti-neurali-attraverso-algoritmi-genetici-in-c-parte-iii/#comments</comments>
		<pubDate>Fri, 28 Nov 2008 22:14:33 +0000</pubDate>
		<dc:creator>Francesco</dc:creator>
				<category><![CDATA[Informatica]]></category>
		<category><![CDATA[Algoritmi genetici]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[Intelligenza artificiale]]></category>
		<category><![CDATA[Reti neurali]]></category>

		<guid isPermaLink="false">http://mindunpacked.com/?p=132</guid>
		<description><![CDATA[IMPLEMENTAZIONE
Ok, siamo arrivati alla parte più tecnica cioè all&#8217;implementazione vera e propria della rete. Ho scelto di utilizzare il C++ e di programmare tutto ad oggetti perchè, anche se questo approccio sacrifica forse un po&#8217; la velocità, rende, almeno per me, il tutto più comprensibile e riutilizzabile (dalle classi che qui espongo ho costruito poi [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: center;"><strong>IMPLEMENTAZIONE</strong></p>
<p align="justify">Ok, siamo arrivati alla parte più tecnica cioè all&#8217;implementazione vera e propria della rete. Ho scelto di utilizzare il C++ e di programmare tutto ad oggetti perchè, anche se questo approccio sacrifica forse un po&#8217; la velocità, rende, almeno per me, il tutto più comprensibile e riutilizzabile (dalle classi che qui espongo ho costruito poi una libreria per l&#8217;utilizzo delle reti neurali).</p>
<p><span id="more-132"></span></p>
<p align="justify">Cominciamo a partire dalle classi della rete neurale.</p>
<p align="center"><strong>Le classi Neuron, NeuronLayer e NeuralNet </strong></p>
<p align="justify">La prima classe che implementeremo è la classe <strong>Neuron</strong>, che rappresenta la struttura più piccola della rete neurale: il neurone.</p>
<p align="justify">Ogni neurone come abbiamo visto ha dei collegamenti pesati in entrata (tranne i neuroni di input) e un valore, che è contiene il valore del neurone.</p>
<p align="justify">Il codice della classe Neuron è il seguente:</p>
<pre class="brush: cpp;">
class Neuron {
	public:
		Neuron(int c_numWeights);
		void setValue(double v);
		double getValue() const;
		void setWeight(int i, double v);
		double getWeight(int i) const;
		int getWeightsNum(bool bias) const;
	private:
		double value;
		vector&lt;double&gt; weights;
};
</pre>
<p>I metodi di questa classe sono tutti molto facili da capire: riporto qui solamente il codice del costrutture e di getWeightsNum(bool):</p>
<pre class="brush: cpp;">
// Costruttore
Neuron::Neuron(int c_numWeights) {
	for (int i = 0; i &lt; c_numWeights+1; i++) {
		weights.push_back(wRand());
	}
}
int Neuron::getWeightsNum(bool bias) const {
	return (bias) ? weights.size() : weights.size() 1;
}
</pre>
<p align="justify">Il costruttore riceve come argomento il numero dei pesi in entrata per questo neurone e li inizializza a valori random (wRand() è una funzione definita in un file header che restituisce un numero compreso tra -1 e 1). Se osservate bene il ciclo va da 0 a c_numWeights+1 questo perchè viene creato un peso aggiuntivo chiamato bias, la cui funzione vi sarà chiara fra poco.</p>
<p align="justify">Nella classe Neuron avremmo potuto anche creare un puntatore a funzione che puntasse alla funzione di attivazione (o funzione di trasferimento) del neurone ed in questa maniera avremmo potuto impostare una funzione di attivazione diversa per ogni neurone (o per ogni livello), ma visto che la nostra funzione sarà uguale per tutti i neuroni, ho preferito non farlo per questioni di semplicità.</p>
<p align="justify">E&#8217; arrivato il momento di spendere due parole proprio sulle funzioni di attivazione. La <strong>funzione di attivazione</strong> può essere una qualunque funzione, come per esempio , ma alcune offrono risultati migliori in base al contesto nella quale sono utilizzate. Scegliere la funzione giusta può essere determinante per ottenere buoni risultati.</p>
<p align="justify">Vediamo alcune funzioni comunemente usate:</p>
<p align="justify">
<p align="justify"><strong>Funzione a gradino: y = 1 per x &gt;= 0, 0 per x &lt; 0</strong></p>
<p align="justify">La funzione a gradino (chiamata così per il suo grafico) è la funzione che più rispetta il comportamento del <strong>neurone biologico</strong>. Infatti essa restituisce 1, cioè propaga il segnale, se la somma degli input ricevuti e maggiore o uguale a un certo numero , che altro non è che la soglia di attivazione. E&#8217; utile utilizzare questa funzione quando vogliamo che la nostra rete abbia un risultato che o 1 o 0 e che quindi separi gli input che gli forniamo in due classi distinte.</p>
<p align="justify">
<p align="justify"><span style="color: #808080;"><strong>Funzione identità: y = x</strong></span></p>
<p align="justify">Non penso ci sia molto da dire su questa funzione, l&#8217;unica cosa da sapere è che si utilizza quando il nostro output non è limitato e può variare da meno infinito a più infinito.</p>
<p align="justify">
<p align="justify"><strong>Funzione sigmoidale: y = 1/(1+e^(-x)) </strong></p>
<p align="justify">
<p align="justify">La funzione sigmoidale è una delle funzioni più utilizzate. Essa passa sempre per il punto (0, 1/2) ed è compresa tra 0 e 1. Proprio per quest&#8217;ultimo fatto non può essere utilizzata se ci aspettiamo come output numeri numeri che non sono compresi in questo intervallo, per i quali è necessario utilizzare altre funzioni.</p>
<p align="justify">
<p align="justify">
<p align="justify"><strong>Tangente iperbolica: y = tanh(x)</strong></p>
<p align="justify">La tangente iperbolica è molto simile alla funzione sigmoidale solo che il suo output è compreso tra -1 e 1 e passa sempre per l&#8217;origine. Come al solito va utilizzata solo nei casi in cui l&#8217;output deve essere compreso tra questi valori e per esempio non andrebbe bene se volessimo allenare la rete a fare la somma di due numeri qualsiasi. In realtà le cose non stanno esattamente così, perchè, come vedremo in seguito, esiste un apposito valore (bias) per ogni neurone che serve a spostare il centro della funzione e quindi ad ottenere valori che non sono più compresi tra -1 e 1 ma tra meno infinito  e  più infinito.</p>
<p align="justify">In ogni caso è comunque preferibile una funzione di trasferimento lineare nei casi in cui il nostro output possa variare in maniera illimitata.</p>
<p align="justify">
<p><!--adsense--></p>
<p align="justify">Dopo questa parentesi a proposito delle <strong>funzioni di attivazion</strong>e torniamo alla nostra implementazione. Una volta che il neurone fa la sommatoria pesata di tutti gli input ricevuti passa questo valore alla funzione di attivazione che, a sua volta, restituisce un altro valore. Quest&#8217;ultimo sarà propagato ai neuroni successivi e così via.</p>
<p align="justify">La seconda classe di cui ci occuperemo è NeuronLayer, che rappresenta uno strato di neuroni:</p>
<p align="justify">
<pre class="brush: cpp;">
class NeuronLayer {
	public:
		NeuronLayer(int c_numNeurons, int c_weightsPerNeuron);
		Neuron* getNeuron(int i) const;
		int getNeuronsNum() const;
	private:
		vector&lt;Neuron*&gt; neurons;
};
</pre>
<p align="justify">
<p align="justify">Come è logico, la classe <strong>NeuronLayer</strong> dovrà contenere un insieme di neuroni e per questo usiamo la classe vector della STL per istanziare un vettore di oggetti Neuron*.</p>
<p align="justify">Anche qui i metodi sono abbastanza semplici: il costruttore riceve come parametri il numero dei neuroni facenti parte del layer ed il numero di collegamenti in entrata (e quindi di pesi) per ogni neurone. La funzione getNeuron(int) riceve come parametro un intero i e restituisce l&#8217;i-esimo neurone del livello; l&#8217;ultima funzione restituisce il numero totale dei neuroni facenti parti del livello.</p>
<p align="justify">
<p align="justify">Siamo giunti alla parte cruciale del nostro programma e cioè la classe NeuralNet.</p>
<p align="justify">Sarà lei che si occuperà di collegare i neuroni fra di loro, di propagare i segnali attraverso i neuroni e di darci l&#8217;output restituito dalla rete.</p>
<p align="justify">
<pre class="brush: cpp;">
class NeuralNet {
	public:
		NeuralNet(int c_numInputNeurons, int c_numOutputNeurons,
		int c_numHiddenLayers, int c_numNeuronsPerLayer);
		void createNet();
		void run(vector&lt;double&gt; input, Chromosome* d);
		int totalNumWeights(bool bias);
		void dump();
		double globalError(vector&lt;double&gt; des);
		void printOutput();
	private:
		vector&lt;NeuronLayer*&gt; layers;
		int numInputNeurons,
		numOutputNeurons,
		numHiddenLayers,
		numNeuronsPerLayer;
}
</pre>
<p align="justify">
<p align="justify">Il costruttore della classe <strong>NeuralNet</strong> riceve in input 4 parametri che sono rispettivamente il numero dei neuroni di input, il numero dei neuroni di output, il numero dei livelli nascosti e il numero di neuroni contenuti nei livelli nascosti.</p>
<p align="justify">Il costruttore non fa altro che prendere questi argomenti e salvarli nelle quattro variabili apposite. Il vettore layers contiene dei puntatori ad oggetti NeuronLayer che saranno appunto i vari livelli della rete neurale. Due sono i metodi più importanti di questa classe: createNet() e run(vector&lt;double&gt;, Chromosome*). Il primo inizializza l&#8217;array layers creando i livelli necessari ed i collegamenti tra i vari neuroni, mentre il secondo, esegue la rete neurale passandogli in input i valori contenuti nell&#8217;array input ed utilizzando come pesi della rete il DNA dell&#8217;oggeto Chromosome*. Vediamo il codice di queste due funzioni:</p>
<pre class="brush: cpp;">
void NeuralNet::createNet() {
	if (numHiddenLayers &gt; 0) {
		// Se ci sono layer nascosti li crea
		NeuronLayer* HL = new NeuronLayer(numNeuronsPerLayer,
							numInputNeurons);
		layers.push_back(HL);
		for (int i = 1; i &lt; numHiddenLayers; i++) {
			NeuronLayer* HL = new NeuronLayer(numNeuronsPerLayer,
								numNeuronsPerLayer);
			layers.push_back(HL);
		}
		NeuronLayer* OL = new NeuronLayer(numOutputNeurons,
							numNeuronsPerLayer);
		layers.push_back(OL);
	} else {
		NeuronLayer* OL = new NeuronLayer(numOutputNeurons,
							numInputNeurons);
		layers.push_back(OL);
	}
}
</pre>
<p align="justify">La prima cosa che la funzione fa è quella di verificare se deve creare dei <strong>layer nascosti</strong> o meno. Nel primo caso crea il primo layer nacosto in cui ogni neurone ha un numero di pesi pari al numero dei neuroni in input (infatti i neuroni del primo layer ricevono i dati proprio dai neuroni di input)  e crea i layer seguenti in cui ogni neurone ha un numero di pesi pari al numero di neuroni presenti negli strati precedenti a lui, che essendo tutti strati nascosti avranno un numero di neuroni pari al contenuto della variabile numNeuronsPerLayer; come ultima cosa viene creato il layer di output. Se non ci sono layer nascosto la prima parte viene saltata e viene creato un layer di output collegato direttamente a quello di input.</p>
<p><!--adsense--></p>
<p align="justify">La funzione run() è un po più complessa. Ho evitato di scriverla tutta qui per problemi di impagnazione, quindi vi conviene leggerla direttamente dal file sorgente. Comunque, la prima cosa che la funziona fa è controllare che il numero degli input ricevuti dalla funzione corrisponda effettivamente al numero di neuroni di input: se così non è l&#8217;esecuzione del programma termina dopo aver stampato un messaggio di errore.</p>
<p align="justify">Successivamente la funzione deve impostare i pesi della rete neurale con il DNA del <strong>cromosoma</strong> che gli passiamo come argomento, per fare questo si utilizzano tre cicli for annidati: il primo scorre tutti i livelli della rete neurale, il secondo tutti i neuroni di ogni livello ed il terzo tutti i pesi di ogni neurone, sosituendoli con quelli presenti nel cromosoma.</p>
<p align="justify">Dopo aver impostato i pesi non ci resta altro che dare alla rete l&#8217;input e propagarlo attraverso i neuroni. Si usano anche qui tre cicli for annidati per scorrere tutti i neuroni della rete neurale e per calcolare la somma degli input pesati. Notate che c&#8217;è un if che distingue due casi: se ci troviamo al primo livello nascosto l&#8217;input dovremo prenderlo dai neuroni di input (che altro non sono che gli elementi dell&#8217;array passato come argomento): questo lo facciamo alla linea:</p>
<p align="justify">
<pre class="brush: cpp;">
totInput += layers[i]-&gt;getNeuron(j)-&gt;getWeight(k) * input[k];
</pre>
<p align="justify">
<p align="justify">Come vedete, il k-esimo peso del neurone viene moltiplicato per il k-esimo input, che altro non è che un valore dall&#8217;array.</p>
<p align="justify">Quando non siamo più al primo livello, ma a quelli successivi l&#8217;input andrà preso da neuroni precedenti ed infatti:</p>
<p align="justify">
<pre class="brush: cpp;">
totInput += layers[i]-&gt;getNeuron(j)-&gt;getWeight(k) * layers[i-1]-&gt;getNeuron(k)&gt;getValue();
</pre>
<p align="left">
<p align="justify">Il k-esimo peso del neurone viene moltiplicato per il valore contenuto nel k-esimo neurone del livello precedente (layers[i-1]). La backslash dopo il * sta solamente ad indicare che la linea è spezzata per ragioni di formattazione, ma che il codice va su una sola riga. La variabile totInput conterrà alla fine del ciclo la sommatoria pesata degli input del neurone. Subito dopo il ciclo viene definita una variabile con il valore dell&#8217;ultimo peso del neurone (questo peso non è stato preso in considerazione quando facevamo la sommatoria, se notate, nel ciclo abbiamo passato il parametro false alla funzione getWeightsNum() facendoci così restituire il numero dei pesi meno 1). Questo sarà il bias che alla riga successiva viene sottratto al valore totale del  neurone dopo che quest&#8217;ultimo è stato passato attraverso la funzione sigmoid() cioè la funzione di trasferimento sigmoidale. Dal punto di vista grafico potete immaginare il bias semplicemente come una traslazione sull&#8217;asse y del grafico della funzione e questo comporta che la funzione non sia centrata nel punto per ogni neurone ma che ogni neurone abbia appunto una funzione centrata in un punto differente.</p>
<p align="justify">Il compito della funzione è finito qui, poiché dopo tutti questi cicli i neuroni dell&#8217;ultimo livello, cioè i neuroni di output conterrano il risultato ottenuto dalla rete.</p>
<p align="justify">L&#8217;ultima funzione degna di nota è globalError(): essa calcola l&#8217;errore della rete facendo la differenza tra ogni output ed il rispettivo output desiderato specificato nel training set. Ci servirà in seguito per assegnare il fitness ad i nostri cromosomi.</p>
<p align="justify">Nella prossima parte parleremo delle classi relative alla gestione dei cromosomi e metteremo in pratica quello che abbiamo visto teoricamente nella parte seconda quindi continuate a visitarci!</p>
<p align="justify">Link alle parti precedenti:</p>
<p align="justify"><a title="Reti neurali attraverso algoritmi genetici in C++. Parte I" href="http://mindunpacked.com/2008/reti-neurali-attraverso-algoritmi-genetici-in-c-parte-i/" target="_self">Parte I</a></p>
<p align="justify"><a title="Reti neurali attraverso algoritmi genetici in C++. Parte II" href="http://mindunpacked.com/2008/reti-neurali-attraverso-algoritmi-genetici-in-c-parte-ii/" target="_self">Parte II</a></p>
]]></content:encoded>
			<wfw:commentRss>http://mindunpacked.com/2008/reti-neurali-attraverso-algoritmi-genetici-in-c-parte-iii/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Reti neurali attraverso algoritmi genetici in C++. Parte I</title>
		<link>http://mindunpacked.com/2008/reti-neurali-attraverso-algoritmi-genetici-in-c-parte-i/</link>
		<comments>http://mindunpacked.com/2008/reti-neurali-attraverso-algoritmi-genetici-in-c-parte-i/#comments</comments>
		<pubDate>Wed, 19 Nov 2008 23:05:10 +0000</pubDate>
		<dc:creator>Francesco</dc:creator>
				<category><![CDATA[Informatica]]></category>
		<category><![CDATA[Algoritmi genetici]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[Intelligenza artificiale]]></category>
		<category><![CDATA[Reti neurali]]></category>

		<guid isPermaLink="false">http://mindunpacked.com/?p=37</guid>
		<description><![CDATA[PREFAZIONE
Le reti neurali sono un argomento molto ostico per molti all&#8217;inizio.
Anche io per riuscire ad implementare la mia prima rete neurale funzionante ci ho impiegato molto tempo ma ho soprattutto dovuto provare e riprovare più volte passando per diversi fallimenti. Mi sono accorto che molti dei tutorial che si trovano in giro tralasciano alcuni aspetti [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: center"><strong>PREFAZIONE</strong></p>
<p style="text-align: justify;">Le <strong>reti neurali</strong> sono un argomento molto ostico per molti all&#8217;inizio.<br />
Anche io per riuscire ad implementare la mia prima <strong>rete neurale</strong> funzionante ci ho impiegato molto tempo ma ho soprattutto dovuto provare e riprovare più volte passando per diversi fallimenti. Mi sono accorto che molti dei tutorial che si trovano in giro tralasciano alcuni aspetti o li spiegano in maniera poco chiara, e tra l&#8217;altro i tutorial in lingua italiana sull&#8217;argomento sono anche pochi.<br />
Con questo tutorial cercherò di creare un documento che comprenda almeno le basi per rendere chiunque lo legga, ed abbia alcuni prerequisiti elencati in seguito, capace di implementare una rete neurale.<br />
<span id="more-37"></span></p>
<p style="text-align: center"><strong>Nota sul codice.</strong></p>
<p style="text-align: justify;">Prima di iniziare va scritta una piccola nota sul codice: il codice che troverete nell&#8217;archivio che vi sarà dato alla fine di questa guida, non è esattamente lo stesso che trovate scritto in questa serie di tutorial. Questo perchè ho fatto in seguito delle modifiche (minori) che comunque non cambiano in sostanza la struttura del codice, ma aggiungono solo qualche funzionalità alla rete neurale. Non dovrebbe essere difficile seguirlo lo stesso.</p>
<p style="text-align: center"><strong>PREREQUISITI</strong></p>
<p style="text-align: justify;">Ho cercato di rendere questa guida comprensibile alla maggior parte delle persone (anche a quelle che sull&#8217;argomento reti neurali sono poco informate) ma restano sempre degli argomenti che vengono dati per scontati per la comprensione del testo.<br />
Sono:</p>
<ul>
<li>Buona conoscenza del C++ e della programmazione OO</li>
<li>Basi matematiche</li>
<li>Conoscenza degli <strong>algoritmi genetici</strong></li>
</ul>
<p style="text-align: justify;">L&#8217;ultimo punto non è strettamente necessario, visto che tenterò di spiegare almeno quello che serve sapere sugli algoritmi genetici per implementare la nostra rete, ma se avete gia&#8217; una conoscenza dell&#8217;argomento di certo avrete meno difficoltà a comprendere alcuni concetti. Alla fine del tutorial sono consigliati una serie di link utili la cui lettura e caldamente consigliata.</p>
<p style="text-align: center"><strong>PARTE GENERALE</strong></p>
<p style="text-align: center"><strong>Introduzione.</strong></p>
<p style="text-align: justify;">Questa Parte generale del tutorial contiene alcuni elementi di base come il funzionamento di un <strong>neurone</strong> biologico, la struttura di un neurone artificiale (cioè quello che noi implementeremo) e la struttura di una rete neurale artificiale. Ho inserito anche una piccola parte sugli <strong>algoritmi genetici</strong> che non tratta esaustivamente l&#8217;argomento ma dovrebbe dare almeno l&#8217;infarinatura necessaria a comprendere per quale motivo li useremo e come li useremo. Comunque, come ho scritto sopra, consiglio lo stesso la lettura di altri tutorial più approfonditi se avete difficoltà a comprendere quello che dico sugli algoritmi genetici. Avrei tralasciato volentieri questa parte, perchè penso che molti di voi già la conoscano se hanno letto almeno qualche altro documento sull&#8217;argomento reti neurali. Purtroppo mi tocca scriverla lo stesso visto che è un requisito fondamentale per la<br />
comprensione delle parti successive e questo tutorial mira ad essere il più chiaro possibile anche per chi è agli inizi. Comunque, se conoscete già questi argomenti potete tranquillamente saltare tutta la Parte generale del tutorial e passare a leggere direttamente il resto.<br />
<!--adsense--></p>
<p style="text-align: center;"><strong>Come funziona un neurone biologico.</strong></p>
<p style="text-align: justify;">I neuroni sono le cellule che costituiscono la nostra mente e che trasmettono i segnali nervosi (sia tra di loro che verso le altre parti del corpo). Ogni uomo posside circa 100 miliardi di neuroni (o almeno dovrebbe) variamente collegati tra di loro attraverso una struttura che prende il nome di sinapsi.<br />
Ogni neurone possiede un lungo prolungamento chiamato assone e diverse ramificazioni più piccole che prendono il nome di dendriti. Attraverso i dendriti (che sono collegati agli assoni di altri neuroni) la cellula riceve i segnali che gli vengono inviati, mentre attraverso l&#8217;assone viene mandato un nuovo segnale.<br />
Se non avete ben chiaro cio&#8217; che abbiamo detto fino ad ora, l&#8217;immagine seguente dovrebbe chiarvi le idee:</p>
<div class="wp-caption alignnone" style="width: 410px"><img title="Schema di un neurone biologico" src="http://mindunpacked.com/images/neuron.bmp" alt="Schema di un neurone biologico" width="400" height="216" /><p class="wp-caption-text">Schema di un neurone biologico</p></div>
<p style="text-align: justify;">(Nella figura sono presenti parti del neurone che non ho nominato, come per esempio la guaina mielinica, perche&#8217; non sono utili al nostro scopo).<br />
In generale, quando un neurone riceve un segnale, se esso supera una certa soglia (detta soglia di attivazione), propaga quel segnale attraverso il suo assone agli altri neuroni, altrimenti resta inattivo.</p>
<p style="text-align: center"><strong>Come funziona una rete neurale.</strong></p>
<p style="text-align: justify;">Un <strong>neurone artificiale</strong> tenta di emulare il comportamento di quello biologico, anche se in maniera molto semplificata.<br />
Ogni neurone (d&#8217;ora in poi con il termine neurone mi riferirò esclusivamente a quelli artificiali) ha una serie di collegamenti pesati in ingresso e  fornisce un output in base agli input ricevuti dai collegamenti. Per collegamento pesato si intende un collegamento al quale è anche associato un peso,<br />
che rappresenta, in poche parole, la forza del collegamento e quindi quanto esso potrà influenzare l&#8217;output del neurone.<br />
Il peso non è altro che un numero, generalmente compreso tra 0 e 1 (o tra 1e 1).<br />
L&#8217;informazione trasportata dal collegamento (parliamo sempre di un numero) viene moltiplicata per il peso e quindi varia al variare del peso (resta invariata quando esso è uguale a 1, diventa nulla quando è 0 e diventa l&#8217;opposto quando è 1).<br />
Come vedremo, sarà proprio il valore dei pesi a determinare l&#8217;esattezza dei risultati della nostra rete ed è appunto variando i pesi tramite speciali algoritmi che si tenta di raggiungere una configurazione ottimale. Ricordo che i pesi subito dopo l&#8217;inizializzazione della rete hanno valori casuali.<br />
Il neurone, dopo aver ricevuto gli input pesati da tutti i collegamenti in ingresso li somma. La sommatoria degli input pesati viene poi passata ad una funzione chiamata funzione di attivazione che fa propagare il segnale ai neuroni successivi.<br />
Spesso, e questo comportamento differisce da quello del neurone biologico, non viene stabilita una soglia minima di attivazione al di sotto della quale il neurone non invia nessuno stimolo, ma questo dipende dalla funzione di attivazione scelta e lo vedremo più tardi.<br />
Le reti che andremo ad implementare in questo tutorial sono definite <strong>reti feedforward</strong> perchè l&#8217;impulso si propaga sempre nella stessa direzione; esistono molti altri tipi di reti e ognuna è più adatta ad alcuni compiti particolari, ma non ne parleremo in questo tutorial.<br />
Una rete neurale è formata appunto da un certo numero di neuroni, chiaramente molto minore di quello del nostro cervello: in genere alcune decine di neuroni sono in grado di compiere compiti anche piuttosto complessi.<br />
I neuroni di una rete sono organizzati in diversi livelli, o strati, e ognuno di essi ha un compito preciso. Il primo strato è quello di input: contiene i neuroni che ricevono l&#8217;input e non hanno collegamenti pesati; non essendo infatti i dati che ricevono provenienti da nessun altro neurone essi immagazzinano semplicemente il dato così come è e lo trasmettono al livello successivo.<br />
Lo strato di input può essere collegato direttamente a quello di output oppure tra di essi si può trovare un certo numero di strati nascosti (<strong>hidden layers</strong>): per gli scopi di questo tutorial useremo una rete con un solo strato nascosto il quale è più che sufficiente per svolgere i compiti che ci interessano.</p>
<p style="text-align: justify;">Abbiamo visto la struttura di una rete neurale, ma come fa essa ad apprendere? Va detto che esistono due tipi di <strong>apprendimento</strong>: quello <strong>supervisionato</strong> (che tratteremo in questo tutorial) e quello non supervisionato.</p>
<p style="text-align: justify;">Usando il primo tipo di apprendimento la rete necessita di una prima fase di addestramento durante la quale le vengono forniti alcuni esempi comprendenti sia l&#8217;input che l&#8217;output desiderato. La rete viene eseguita con questi input di cui si conosce già in precedenza il risultato e tramite alcuni algoritmi vengono modificati i pesi della rete per fornire risultati sempre più accurati. Quando la fase di allenamento è finita (cioè si e&#8217; raggiunta una soglia minima di errore stabilita in precedenza) la rete è in grando non solo di dare un risultato esatto se gli forniamo gli stessi dati che gli<br />
abbiamo fornito nel <strong>training set</strong> (gli esempi) ma anche con dati in input che non ha mai visto. Questo avviene perchè la rete non associa un singolo input all&#8217;output corrispondente ma scopre la relazione che li lega. Potremmo per esempio allenare una <strong>rete neurale</strong> ad imparare a fare la somma di due numeri fornendo un training set del genere:</p>
<table style="text-align: center" border="0">
<tbody>
<tr>
<td>Primo input</td>
<td>Secondo input</td>
<td>Output desiderato</td>
</tr>
<tr>
<td>0.1</td>
<td>0.2</td>
<td>0.3</td>
</tr>
<tr>
<td>0.1</td>
<td>0.3</td>
<td>0.4</td>
</tr>
<tr>
<td>0.1</td>
<td>0.4</td>
<td>0.5</td>
</tr>
<tr>
<td>0.1</td>
<td>0.5</td>
<td>0.6</td>
</tr>
<tr>
<td>0.1</td>
<td>0.6</td>
<td>0.7</td>
</tr>
<tr>
<td>0.1</td>
<td>0.7</td>
<td>0.8</td>
</tr>
<tr>
<td>etc&#8230;</td>
<td>etc&#8230;</td>
<td>etc..</td>
</tr>
</tbody>
</table>
<p><!--adsense--></p>
<p style="text-align: justify;">Un training set deve essere il più omogeneo possibile, e deve descrivere una grande varietà di esempi. Un training set in cui il primo input è sempre 0.1 non è per niente buono per ottenere dei risultati soddisfacenti. Più è vasto il training set, inoltre, più sarà alta la <strong>capacità di generalizzazione</strong> della rete, cioè di dare risultati corretti anche quando i dati in input sono per lei sconosciuti, cioè non facevano parte del training set.<br />
Modificando in maniera corretta i pesi della rete essa riconosce la relazione tra gli input e l&#8217;output (e cioè, nel nostro caso, che l&#8217;output deve essere la somma degli input) e dà un risultato corretto. Ricordatevi comunque che l&#8217;applicazione delle reti neurali avviene in campi in cui è più importante la flessibilità e la capacità di generalizzazione della stessa, piuttosto che ottenere risultati precisissimi: quello che voglio dire è che una rete neurale è molto più utile per la sua flessibilità che per la sua precisione, e che per fare la somma di dui numeri è molto meglio usare una calcolatrice. Una rete<br />
addestrata a tale scopo, infatti, dà in genere, risultati approssimati come :<br />
0.5 + 0.5 = 0.99<br />
0.1 + 0.9 = 1.02<br />
o simili.<br />
Chiusa questa piccola parentesi torniamo ai tipi di apprendimento. Il secondo tipo di apprendimento (quello non supervisionato) serve a creare reti<br />
neurali che classificano i dati che gli forniamo in input in diverse categorie (senza fornigli nessun output desiderato, da qui il nome) in base ai loro elementi in comune, ma non verra&#8217; trattato in questo tutorial.<br />
Come avrete capito, la parte più importante per l&#8217;apprendimento della rete neurale è la modifica dei pesi fra le connessioni dei neuroni ed è proprio qui che agiscono gli <strong>algoritmi di apprendimento</strong>. Esistono diversi algoritmi: uno dei piu&#8217; famosi è quello di retro propagazione dell&#8217;errore (error back propagation) che mi limiterò a citare solamente visto che noi faremo uso di algoritmi genetici per fare evolvere la nostra rete.</p>
<p>La prima parte del tutorial finisce qui. A presto.</p>
]]></content:encoded>
			<wfw:commentRss>http://mindunpacked.com/2008/reti-neurali-attraverso-algoritmi-genetici-in-c-parte-i/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

<!-- www.000webhost.com Analytics Code -->
<script type="text/javascript" src="http://analytics.hosting24.com/count.php"></script>
<noscript><a href="http://www.hosting24.com/"><img src="http://analytics.hosting24.com/count.php" alt="web hosting" /></a></noscript>
<!-- End Of Analytics Code -->
