Si pensa spesso che grandi rivoluzioni siano accompagnate da grandi e complicate implementazioni. Tuttavia la storia ci insegna che le grandi idee spesso sono le più semplici.

Nell’IA sono proprio queste idee semplici a dare i migliori risultati. Fra queste un ottimo esempio è dato dall Reti Neurali. Questo modello matematico consiste, fondamentalmente, nell’interconnessione di unità a soglia.

Non entrerò nei dettagli matematici di una rete neurale ma voglio mostrare un codice di 290 righe (commenti e linee vuote incluse)  che implementano una semplicissima rete neurale non ricorsiva addestrata a con retropropagazione.

Non  credo sia la versione più “elegante” ne la più ottimizzata ma funziona discretamente.

# -*- coding: utf-8 -*-
"""
Modulo che contiene classi e metodi per rappresentare
una rete neurale non ricorsiva.

Modulo Didattico
"""


import math

class Sigmoid :
  """
  Rappresenta una singola unità sigmoide.
  """


  def __init__(self, num_in = 0) :
    """
    Costruttore.

      Args:
        num_in (int) Numero di ingressi della rete neurale.
    """

    self.w = [1.0]*num_in
    self.delta_value = [0,0]

  def __repr__(self) :
    return repr(self.w)

  @staticmethod
  def scalar(v1, v2) :
    """
    STATIC. Prodotto scalare fra i vettori v1 e v2.

      Args:
        v1 (vector) Vettore 1
        v2 (vector) Vettore 2

      Returns:
        Il prodotto scalare fra v1 e v2. (double)
    """

    res = 0
    for i in range(len(v1)) :
      res += v1[i]*v2[i]
    return res

  def sigma(self, ingresso) :
    """
    Ritorna il valore della funzione sigma del prodotto scalare fra
    ingresso e i pesi del sigmoide.

      Args:
        ingresso (vector) Vettore d'igresso

      Returns:
        Il valore della funzione sigma. (double)
    """

    s = Sigmoid.scalar(self.w, ingresso)
    return 1 / (1 + math.e**(-s))

  def activate(self, ingresso) :
    """
    Ritorna il valore di soglia per il prodotto scalare fra
    l'ingresso e i pesi del sigmoide.

      Args:
        ingresso (vector) Vettore d'ingresso.

      Returns:
        1 se il prodotto scalare è maggiore di zero, 0 altrimenti.
    """

    s = Sigmoid.scalar(self.w, ingresso)
    if s > 0 : return 1
    return 0

  def add_in(self, w = 0) :
    """
     Aggiunge un ingresso al sigmoide.

      Args:
        w (double) Peso del nuovo ingresso.
    """

    self.w.append(w)

  def change(self, i, new) :
    """
    Cambia il valore del peso dell'ingresso i-esimo.

      Args:
        i (int) Numero dell'ingresso.
        new (double) Nuovo peso per l'ingresso.
    """

    if i > len(self.w) :
      print "ERROR: "
      return
    self.w[i] = new
    self.delta_value[0] = 0

class NeuralNet :
  """
  Classe che rappresenta una rete neurale generica non ricorsiva.
  """


  def __init__(self, n_in) :
    """
    Costruttore.

    Il numero di ingressi NON comprende l'ingresso fittizio
    che simula la soglia.

      Args:
        n_in (int) Numero di ingressi della rete.
    """

    self.units = []
    self.n_in = n_in

  def __repr__(self) :
    return repr(self.units)

  def add_strate(self) :
    """
    Aggiunge uno strato alla rete.
    """

    self.units.append([])

  def add_unit(self, j, w = None) :
    """
    Aggiunge un unità sigmoide allo strato j.

      Args:
        j (int) Numero di strato.
        w (vector) Vettore dei pesi della nuova unità.
    """

    if j >= len(self.units) :
      print "ERROR: "
      return

    # Se è il primo strato i sigmoidi hanno un numero di ingressi
    # pari al numero di ingressi della rete più  l'ingresso fittizio.
    # Altrimenti è pari al numero dei sigmoidi dello strato precedente
    # più l'ingresso fittizio.
    if j == 0 :
      sig = Sigmoid(self.n_in + 1)
    else :
      sig = Sigmoid(len(self.units[j-1]) + 1)
    self.units[j].append(sig)

    # Aggiorna il peso del nuovo sigmoide con i pesi nel vettore W.
    if w != None and len(w) == len(sig.w):
      p = 0
      for i in w :
        sig.change(p, i)
        p+=1

    # Se NON è l'ultimo strato bisogna aggiungere un ingresso a tutti
    # i sigmoidi dello strato successivo.
    if j != ( len(self.units) - 1 ) :
      for i in self.units[j+1] :
        i.add_in()

  def activate(self, ingresso) :
    """
    Attiva la rete neurale sull'ingresso 'ingresso'. Il
    vettore di ingresso NON contiene il vettore fittizio.

      Args:
        ingresso (vector) vettore di ingresso.

      Returns:
        uscita (vector) vettoore di uscita.
    """

    if len(ingresso) != self.n_in :
      print "ERRORE"
      return

    current = ingresso[:]
    current.append(1)
    for j in self.units :
      next_in = []
      for i in j :
        next_in.append(i.activate(current))
      current = next_in[:]
      current.append(1)
    return next_in

  def list_f(self, ingresso) :
    """
    Lista le uscite di ogni sigmoide della rete in base
    all'uscita della funzione sigmoide.

      Args:
        ingresso (vector) Vettore di ingresso.

      Returns:
        Il vettore contenente il risultato dell'applicazione di un
        vettore di ingresso PER OGNI sigmoide.
    """

    if len(ingresso) != self.n_in :
      print "ERRORE"
      return

    current = ingresso[:]
    current.append(1)
    res=[]
    for j in self.units :
      next_in = []
      for i in j :
        next_in.append(i.sigma(current))
      current = next_in[:]
      current.append(1)
      res.append(next_in)
    return res

  def delta(self, list_out, strato, sigmoide, desire) :
    """
    Calcola il valore delta per l'i-esimo sigmoide del j-esimo strato.

    La foruma del delta è:

      delta(i,j) = f * (1 - f) * SUM ( delta(j+1, l) )

    dove l varia per ogni sigmoide dello strato successivo.

    Se j = strato finale allora

      delta(i,j) = (desire - f) * f * (1 - f)

      Args:
        list_out (vector) Lista delle uscite della rete.
        strato (int) Numero dello strato.
        sigmoide (int) Numero del sigmoide.
        desire (double) Valore desiderato in uscita per l'ingresso.

      Returns:
        Il valore delta cercato.
    """

    f = list_out[strato][sigmoide]
    sig = self.units[strato][sigmoide]
    if sig.delta_value[0] == 1 :
      return sig.delta_value[1]
    if strato == ( len(self.units) - 1 ) :
      ris = ( desire - f) * f * (1 - f)
    else :
      ris = f*(1-f)
      cumulator = 0
      for l in range(len(self.units[strato + 1])) :
        wijl = self.units[strato+1][l].w[sigmoide]
        cumulator += self.delta(list_out, strato+1, l, desire) * wijl
      ris = ris * cumulator
    sig.delta_value = [1, ris]
    return ris

  def delta_reset(self) :
    """
    Invalida i delta_value dei sigmoidi.
    """

    for j in self.units :
      for i in j :
        i.delta_value[0] = 0

  def train(self, ingresso, desire, c = 1.0) :
    """
    Addestra una rete neurale sull'ingresso inserito.

    La formula dii retro propagazione è

      W(i,j) = W(i,j) + c * delta(i,j) * X(i,j)

    doeve W e X sono vettori.

      Args:
        ingresso (vector) Vettore in ingresso.
        desire (double) Valore desiderato in uscita.
        c (double) Velocità di apprendimento.
    """

    f = self.list_f(ingresso)
    x = f[:]    # Questa lista è come 'f' ma include anche l'ingresso.
                # Sia x che f NON includono gli ingressi fittizi.
    x.insert(0, ingresso)
    for j in range(len(self.units)) :
      for i in range(len(self.units[j])) :
        wij = self.units[j][i].w[:] # Sono i pesi del sigmoide (i,j)
        delta = self.delta(f, j, i, desire)
        for k in range(len(wij)) :
          if k == ( len(x[j]) ) : # Compensa la mancanza dell'ingresso
            xx = 1                # fittizio.
          else :
            xx = x[j][k]
          new = self.units[j][i].w[k] + c * delta * xx
          self.units[j][i].change(k, new)
    self.delta_reset()

Per capire a fondo il codice è necessario conoscere un po’ di teoria sulle reti neurali, per tutti gli altri vi basti notare come una delle più importanti metodologie dell’AI può essere replicata nei suoi tratti essenziali in meno di 300 righe.

 

Probabilmente fra tutti gli esempi di applicazioni dell’Intelligenza Artificiale la più semplice e famosa consiste sicuramente nel gioco 20q. Il gioco in questione funziona così: il giocatore pensa ad un oggetto o ad un animale e il marchingegno tenta di indovinare di cosa si tratta in meno di 20 domande a cui il giocatore può rispondere si o no. Potete trovare una versione online del gioco all’indirizzo http://www.20q.net/. Potrete constatare che in alcuni casi il programma sembra proprio leggervi nella mente con risultati quasi spaventosi.

La versione usata dal sito è piuttosto avanzata ed utilizza le reti neurali e permette quindi una gamma di riposte più vasto (c’è anche forse, probabilmente, a volte, ecc…). Il programma è inoltre in grado di apprendere mentre si gioca: ogni qual volta si gioca, o il programma si arrende richiedendo di inserire l’oggetto a cui si pensava, l’insieme di risposte appena date plasma la struttura dati interna del programma in modo tale che la prossima volta l’oggetto venga riconosciuto più velocemente. È un modello di apprendimento molto basilare ma che è analogo a quello umano percezione-previsione-modifica: il programma riceve dati percettivi (le risposte alle domande), formula un ipotesi (i tentativi di indovinare) e modifica la struttura dati in base all’esito della previsione.

Sarei curioso di sapere se il programma del sito ha qualche contromisura contro il problema del sovra-adattamento: questo tipo di problema affligge gran parte dei modelli decisionali, comprese le reti neurali, ed è causato da un eccessivo adattamento della rete a certi tipi di dati piuttosto che ad altri. Facciamo un esempio. Nel gioco 20q è molto più probabile che il giocatore pensi a cose “banali” come “gatto”, “cane”, “fiore” e simili piuttosto che a “antilope”, “spinterogeno” e “neutrino”. Questo significa che nel corso dell’esistenza del gioco il programma verrà addestrato alla perfezione a riconoscere cani e gatti mentre riceverà poche informazioni riguardo antilopi e neutrini. Possiamo quindi dire che “gatto” e “fiore” e le parole comuni facciano parte dell’insieme di addestramento di una rete. Bene, è possibile dimostrare che una rete sovra-adattata al suo insieme di addestramento indovina, in media, molto meno volte oggetti che non appartengono a tale insieme rispetto ad una rete che è solo parzialmente adattata.

Rimandiamo però questi approfondimenti sulle reti neurali. Il motivo per cui ho scritto questo articolo era di mostrare come sia possibile in una manciata di righe scrivere un programma che emuli in modo semplice il gioco di 20q. Per questa approssimazione consideriamo che sia possibile dare alle domande soltanto le risposte si o no.

Il metodo che vi mostrerò non utilizza nessuna tecnica propria dell’IA bensì dei semplicissimi alberi binari. Questi alberi binari li indicheremo come alberi decisionali binari. Nel nostro albero decisionale definaiamo:

  • I nodi interni dell’albero sono domande.
  • I nodi foglia dell’albero sono gli oggetti da indovinare.
  • Il sotto-albero destro di un nodo corrisponde al caso in cui la risposta alla domanda sia si.
  • Il sotto-albero sinistro di un nodo corrisponde al caso in cui la risposta alla domanda sia no.

L’algoritmo del gioco consiste in una cosa del tipo:

  • Il programma formula la prima domanda che trova (cominciando con il nodo radice).
  • Se non c’è più nessuna domanda il programma si arrende e chiede al giocatore di inserire 1) l’oggetto a cui stava pensando. 2) una domanda che rappresenta l’oggetto 3) la risposta a questa domanda.
  • Il programma aggiunge questa domanda e la relativa risposta al sotto albero in cui si era fermato (oppure come nodo radice se l’albero era vuoto).
  • Se invece la domanda c’è il programma formula la domanda e scende nel sotto-albero relativo alla risposta.
  • Il programma ricomincia dal punto 1.

Tutto qui. Tale algoritmo è effettivamente molto grezzo e sono possibili un gran numero di migliorie (ad esempio usare dei modelli di albero più “elastici” per evitare alberi troppo sbilanciati) ma svolge decentemente il proprio lavoro. Dopo che l’avete fatto girare per qualche tempo vedrete che inizierà ad imparare e ad indovinare un discreto numero di parole. Ovviamente potete partire da un albero vuoto oppure pre-costruire un albero di base con alcune domande comuni.

Un altra cosa che può farci capire questo semplice programma è una considerazione che mi ha fatto notare un gentile commentatore: la capacità degli algoritmi di AI non dipende dalla dimensione del programma ovvero dal suo numero di righe di codice allo stesso modo di come le capacità celebrali umane non dipendono dalla dimensione del cervello (una balena ha il cervello molto più voluminoso di un essere umano eppure fa molte meno cose). Le capacità cognitive di un programma dipendono solamente dalle relazioni che si auto-generano fra le strutture dati del programma (nel nostro caso tali relazioni sono i collegamenti ad albero fra i nodi).

Se qualcuno avesse voglia di creare questo programmino usando il minor numero di righe possibili sarei felice di pubblicarlo. Inoltre potreste anche usarlo per sbalordire amici, parenti e vicini di casa! XD

Alla prossima!

 

L’Intelligenza Artificiale offre sempre spunti interessanti per riflettere su noi stessi. Per prima cosa è bene che sappiate che io sono un fermo sostenitore dell’ IA forte e pienamente convinto che, prima o poi, sarà possibile replicare artificialmente una mente  cosciente di se. Questo non implica che tali agenti intelligenti debbano per forza avere meccanismi di pensiero simili ai nostri, dopotutto la storia scientifica ci insegna che tutte le idee umanocentriche sono sempre state demolite dall’evidenza dei fatti, è quindi poco furbo ipotizzare che il cervello umano sia l’unica forma di “coscienza” possibile nell’universo. Tuttavia il cervello umano è senza dubbio l’unico che conosciamo attualmente e, quindi, è naturale che gran parte dell’IA si affidi a quello come musa ispiratrice e come traguardo.

A sostegno di questa tesi c’è poi la constatazione che, in più di un caso isolato, l’AI è riuscita ad anticipare scoperte che le neuroscienze cognitive avrebbero fatto solo alcuni anni dopo. Un caso fra i tanti è quello delle reti neurali. Una rete neurale non è altro che un sistema di neuroni artificiali (che non sono altro che sommatori pesati collegati ad un meccanismo “a soglia”, ovvero la cui uscita si attiva solamente se l’ingresso supera un certo valore) strettamente collegati fra loro. Tale meccanismo, sebbene composto da elementi relativamente semplici, è in grado di svolgere compiti estremamente complessi come, ad esempio, guidare un auto per centinaia di miglia  (si veda il progetto ALVINN). Queste reti vengono addestrate tramite il meccanismo di retro-propagazione. Questa tecnica consiste, per farla breve, nel modificare i pesi in ingresso ai neuroni artificiali in base al valore di predizione dell’intera rete: ho un dato ingresso x, la rete risponde y, se il valore esatto è y allora la rete non subisce variazioni, se invece il valore giusto era z la rete viene modificata in proporzione alla differenza fra il valore predetto e il valore desiderato. Bene, questo processo è del tutto simile al meccanismo alla base dell’apprendimento nella gran parte degli agenti viventi (non solo l’uomo):  è stato infatti constatato come il cervello rilasci dopamina a seconda se un evento previsto si verifichi o no. L’apprendimento tramite il modello errore-predizione è stato quindi sviluppato dall’AI alcuni anni prima che tale modello venisse formalizzato dai neuroscienziati.

L’AI inoltre ci permette anche di rivalutare molte nostre capacità. Tutti noi sappiamo riconoscere volti o comprendere il linguaggio naturale, ragion per cui consideriamo queste due attività delle cose “facili”. Diversamente solo poche persone sanno giocare bene a scacchi e quindi concludiamo che questo sia un compito “difficile”. In realtà dopo oltre 50 anni di ricerca nelle intelligenze artificiali  abbiamo decine di programmi in grado di giocare stupendamente a scacchi ma ben pochi programmi in grado di riconoscere un volto con prestazioni paragonabili a quelle umane. Questo quindi ci mostra come, in realtà, il giudizio che diamo ai vari problemi sia spesso invertito nel caso delle AI.

Perché? Una prima risposta consiste nel valutare l’importanza di tali problemi. Riconoscere un volto e capire il linguaggio sono cose essenziali a livello evolutivo. Animali che non siano in grado di riconoscere un potenziale predatore o preda da un sasso o da una pozza di lava difficilmente raggiungono l’età adulta, è quindi prevedibile che nel corso dell’evoluzione si siano formati cervelli abilissimi a riconoscere figure forme e colori e meno a giocare a scacchi. Ipoteticamente, infatti, se uccidessimo in fasce tutti i bambini che non siano in grado di giocare a scacchi ad un livello accettabile ci ritroveremmo, fra qualche milione di anni, davanti a esseri dotati di un cervello incredibilmente bravo a giocare a scacchi e, probabilmente, meno bravi a riconoscere un volto.

Il problema dell’evoluzione è quindi cruciale quando cerchiamo di imitare il cervello umano. Dobbiamo sempre tenere presente che il nostro cervello è quello che è perché c’è stata, nel corso delle ere, una pressione evolutiva che lo ha spinto ad avere certe capacità e a non averne altre.

Il secondo punto risiede proprio nella rappresentazione e nel modo in cui essa viene generata. Spesso infatti pretendiamo troppo dalle macchine che progettiamo. Prendiamo ad esempio la percezione visiva. Quando ci troviamo difronte alla percezione visiva ci rendiamo subito conto del problema fondamentale che la divide da problemi “semplici” come il gioco degli scacchi: il rumore. Il gioco degli scacchi è infatti facilmente rappresentabile in termini puramente matematici, è possibile cioè togliere semplicemente tutti gli aspetti rumorosi, ovvero che non danno alcuna informazione aggiuntiva tipo la forma degli scacchi o il colore della scacchiera. Quando invece tentiamo di semplificare la visione vengono alla luce notevoli problemi e domande. Ad esempio il concetto di forma e di bordo: che cos’è una forma? Quand’è che un quadrato a cui arrotondiamo via via gli angoli, smette di essere un quadrato e diventa un cerchio? Come definiamo il bordo di un oggetto data la sua immagine? Sappiamo che le risposte a queste domande sono essenziali per la visione ma non abbiamo idea di come il cervello umano le calcoli.

Abbiamo un gran numero di algoritmi in grado di darci i contorni e  la forma di un oggetto ma tali algoritmi sono spesso complessi, macchinosi ed utilizzano equazioni matematiche non banali sull’intera matrice dell’immagine. Ma, oltre al fatto che tali algoritmi sono piuttosto imprecisi, non è così che funziona l’occhio umano. L’occhio, ad esempio, è in gran parte ceco ad eccezione di una piccola zona centrale. L’impressione di avere un unica grande immagine è del tutto illusoria e prodotta dalla mente. L’immagine quindi è un prodotto della mente non un input percettivo. Perché allora vogliamo che le macchine funzionino direttamente sull’immagine? Non sarebbe meglio concentrarsi su come creare questa immagine partendo da una migliore copia dell’occhio umano? Ad esempio utilizzando i meccanismi basilari dell’uomo quali visione spot (ovvero concentrata al centro)  e rilevatore di movimento nella periferia dell’occhio (che serve a direzionare istintivamente il punto “vedente” dell’occhio in direzione di qualcosa che è cambiato per aggiornare l’immagine mentale). Queste cose potrebbero insegnarci nuovi modi per valutare  figure e bordi (un bordo potrebbe essere segnalato da una variazione repentina della visione (spot) che si avverte mentre l’occhio si muove oppure la forma di un oggetto può essere elaborata anche dal modo in cui l’occhio percorre il suo bordo (infatti quando osserviamo un quadrato, capiamo che è un quadrato percorrendo con gli occhi il bordo del quadrato, non lo facciamo consciamente ma lo facciamo).

Insomma, la neuroscienza ha molto da imparare dall’intelligenza artificiale, ma anche  l’intelligenza artificiale apprende molto dalla prima. Le due discipline si trascinano a vicenda verso nuovi traguardi e molto possiamo aspettarci da entrambe nei prossimi anni. E’ con questa consapevolezza che potremo arrivare un giorno a trovare la chiave, il punto di svolta, quella scoperta che ci farà capire che la soluzione ce l’avevamo da sempre sotto gli occhi. O forse dietro.

 

TerminatorQuest’articolo è uno spunto di riflessione sulle neuroscienze. Non parlo molto dei miei esperimenti di intelligenza artificiale. Non ho ancora ottenuto risultati degni di nota anche perché il mio approccio è completamente diverso dall’approccio classico. L’intelligenza artificiale è popolata di algoritmi e modelli che singolarmente non ci azzeccano nulla con la mente umana. Il problema è, credo, che ci si concentra troppo su aspetti macroscopici.

Programmi in grado di leggere, programmi in grado di ascoltare, programmi che guidano mille miglia nel deserto su piste impreviste. Tutte abilità notevoli che però mancano platealmente il bersaglio. Le macchine eseguono alla perfezione quei lavori ma rimangono macchine proprio perché incapaci di fare altro.

C’è però qualcosa che unisce materia a pensiero. Un anello di congiunzione fra una serie di impulsi e l’auto-coscienza. E’ li che io mi spingo, è quello che mi piace fare.

Così in quest’ultimo anno ho studiato abbastanza la psicologia infantile, in particolare la psicologia neonatale. Questo perché non c’è differenza in atto fra un neonato (e prima ancora un feto) e un complicatissimo schema elettonico per quanto quest’idea sia eticamente raggelante. La differenza sta in cosa queste due macchine sanno fare nativamente. I bambini, si sà, nascono con l’abilità di nutrirsi (il saper ciucciare) e con l’abilità di apprendere. Ed è proprio questa seconda abilità che mi ha sempre affascinato.

Come nasce? Appena nati cosa si sa? Nulla. Non esiste nessuna precondizione nel cervello di un neonato ad esclusione di quelle essenziali informazioni genetiche. Un neonato impara per imitazione, si dice, ma non basta. Non è tutto. Non è possibile che sia tutto: se noi costruissimo una macchina in grado di imitare tutto non sarebbe una macchina molto intelligente.

All’imitazione dobbiamo aggiungere la memoria. La memoria abnorme di un neonato, memoria che però è diversa da quella che utilizziamo in età adulta. Infatti sebbene memorizziamo tonnellate di informazioni nei primi anni di età quasi nessuno di noi riesce a ricordare nulla di quegli anni. Questo significa che tutte quelle informazioni agiscono in modo diverso. Non permangono nel cervello ma lo ristrutturano.

Ma basta? No. Ancora no. Questo meccanismo è simulato dalle reti neurali, strutture dati in grado di ristrutturarsi in base agli input esterni. Eppure le reti neurali non bastano ancora. Allora aggiungiamo i sensi. Non potremo mai evolvere un intelligenza artificiale simile all’intelligenza umana se il tipo di input in grado di ricevere siano diversi da quelli umani.

Ma ancora non basta. Una rete neurale più 5 sensori non da ancora un essere umano. Cosa possiamo aggiungere? L’iterazione del pensiero. Altro non è che una valutazione dell’istinto. Pensiamo a qualcosa, valutiamo se quell’idea è esatta e se non lo è la perfezioniamo. Questo è una bozza di ragionamento. Un qualcosa che può essere simulato da alcune varianti della programmazione genetica.

Ovviamente ancor anon basta. C’è qualcosa che ci sfugge. Che sia un innata abilità nel valutare proposizioni logiche? Può darsi, da adulti non possiamo saperlo. Da adulti il nostro pensiero si unisce totalmente al linguaggio facendoci sfuggire quel qualcosa di primordiale alla base. Quel qualcosa alla base che diamo totalmente per scontato.

Ma quella cosa sicuramente darà dei risultati che ci lasceranno sorpresi. Nel mio piccolo tempo fa avevo preso ad insegnare ad un mio programma (che univa reti neurali a programmazione genetica) a distinguere i poligoni che disegnavo sullo schermo. Ovviamente la cosa è lunghissima, la programmazione genetica è molto lenta già di suo, immaginatela ripetuta per ogni “pensiero” che il programma genera. Ci sono voluti due mesi per fargli distinguere un cerchio da un quadrato. La cosa che mi ha sorpreso però è che il programma alla fine dava segni si squilibrio. Vedeva poligoni che non avevo nemmeno disegnato. Era schizzofrenico.

Mi sono chiesto allora: possibile che tutti i difetti della mente umana (malattie mentali, emozioni incontrollate e molto altro) siano conseguenze obbligate di una struttura cognitiva complessa? Quando l’intelligenza artificiale arriverà ad emulare il comportamento umano avremo necessariamente macchine dotate degli stessi nostri difetti? Avremo macchine malate di mente?

Non so. Non posso esserne sicuro. Ma potremmo avere macchine più umane di quanto vorremmo.

© 2008-2012 SlashCode Suffusion theme by Sayontan Sinha