Contrastive Divergence hält in NNSpace Einzug

So, jetzt ist es soweit, mein erster Prototyp für CD Lernvorgänge mit NNSpace ist fertig. Der Algorithmus kann jetzt über das Training-Menü ausgeführt werden. (Sorry aber die Anwendung steht noch nicht zum Download, weil noch einige wichtige Fehler zu beheben sind, deshalb arbeite ich hier  mal mit Screenshots)

Es ist jetzt ganz einfach ein deep belief network zu trainieren. Und natürlich: Immer nur die Gewichte werden trainiert(wie man rechts im Bild sieht), und die können dann auf eine ganz anders definierte Art und Weise  ausgeführt werden(daran arbeite ich aber noch). Aber ich glaube wir können uns schon mal auf das erste Release freuen.

The principle of neural networks – Eine einfache Sicht auf neuronale Netze

Meine Gedanken schweifen im Moment in die Richtung Abstraktion für neuronale Netze. Irgendwie hab ich den Eindruck, dass mein altes feed-forward Programm nicht mehr ganz aktuell ist, wenn ich auf die deep belief networks schaue. Es ist ja so, dass man(mit einigem Aufwand) so ein deep belief network bauen kann. Sonst gäbe es sie ja nicht. Aber das ist immer mit sehr viel Tipperei verbunden, und nicht jeder, der diese Netze gerne mal austesten würde beherrscht eine Programmiersprache und kennt sich mit den mathematischen Hintergründen aus. Wie Komplex diese Dinger sind merkt man spätestens wenn man mal versucht eins selbst zu programmieren(wie ich es jetzt in C# geschafft hab). ich könnte jetzt meinen Quellcode posten, und vielleicht würde ihn sogar der eine oder andere verstehen, aber irgendwie gefällt mir der Ansatz nicht für jedes dieser Netzte ein neues Programm zu schreiben(was dann auch noch so riesig ist!). Deshalb ja auch schon meine klein Anwendung für feed-forward. Also muss auch für die deep belief networks ein Tool her(meiner Meinung nach). Allerdings findet man im Internet dazu überhaupt nichts, und zumindest die meisten Tools haben die Dinger nicht in ihrer Feature-liste. Die Antwort in den Support Foren ist dann meistens: Haben wir nicht, kriegen wir auch nicht. Und auch bei den Tutorials steht überall: „Man schreibe den Code für …“. Also gibt es noch nicht wirklich ein Tool, was deep lerning Algorithmen bereitstellt. Ok, aber warum nicht? ist es denn wirklich so schwierig? Ich denke ja, und nein. Zunächst: ja, natürlich, komplizierter als Backprop allemal, und wenn  man dann noch wie Hinton Backprop und deep lerning kombinieren will, wirds erst recht kompliziert, wenn nicht sogar unmöglich für die meisten(zum Beispiel mein Programm). Also, warum dann nein? Weil ich der Meinung bin, dass man für so etwas zunächst mal seine Perspektive verändern muss:

Was ist ein neuronales Netz, woraus besteht es?

Alle neuronalen Netze sind doch im Prinzip sehr ähnlich in gewissen Dingen. Da fallen mir eigentlich 3 ein, nämlich: Sie alle haben Gewichte, Schichten, und Abhängigkeiten. Abhängigkeiten heißt: Unit a hängt von Unit b mit dem Gewicht g ab. Schichten deshalb, weil ich einfach zu faul bin über 700 Units einzeln aufzulisten. Wenn das nötig ist befindet sich eben in jeder Schicht nur eine Unit, aber der Benutzer soll  nicht(wie das bei manchen Tools der fall ist) mit einem riesigen Bild von Kreisen die über Striche verbunden sind verärgert werden, weil er da sowieso nicht durchsieht, sondern er soll eine schöne überschaubare Liste haben, die soweit wie möglich zusammengefasst ist. Deshalb: Schichten, und keine Units, das ist der erste wichtige Punkt. Abhängigkeiten definieren dann eben nicht Abhängigkeiten zwischen Units, sondern zwischen Schichten, und Gewichte sind Eigenschaften der Abhängigkeiten. Warum also die Gewichte noch von den Abhängigkeiten trennen, eigentlich gibt es doch(normalerweise) auch nur einfach Gewichte, und nicht noch was drüber. Mein Gedanke war da der folgende: Zum Lernen brauch ich Gewichte, und wirklich nur Gewichte. Ich hab einen Algorithmus, und der verändert Gewichte nach einem bestimmten Schema(natürlich anhand von Lerndaten, die aber nicht Bestandteil des Netzes sind). Das heißt ich trenne die Lernlogik von der Ausführungslogik, was es mir ermöglicht mehrere Gewichte mit unterschiedlichen Algorithmen zu trainieren, und auf eine noch ganz andere selbst definierte Weise auszuführen.

Also haben wir jetzt eine ganz neue Definition von einem neuronalen Netz, die sich viel leichter implementieren lässt. Wie das Programm aussieht, und wie es im konkreten funktioniert, darüber später mehr. Wichtig für mich ist das Folgende: Finden wir eine Definition für alle neuronalen Netze, die so einfach ist, dass sie 1. der Benutzer versteht und anwenden kann, ohne sich über Algorithmen Gedanken machen zu müssen, und die aber auch so genau ist, dass 2. ein Algorithmus genau weiß, was er zu tun hat, und die 3. so dynamisch ist, dass sie auf alle erdenklichen Variationen von implementierten Algorithmen angewandt werden kann, weil: der Algorithmus ändert sich ja nicht, sondern nur die Struktur, wie das Netz ausgeführt wird, oder besser gesagt wie die Gewichte ausgeführt werden.

Demzufolge liegt mir besonders die Trennung von Gewichten und allen anderen Bestandteilen am Herzen, weil die es ermöglicht den Algorithmus immer so zu lassen wie er ist.

Hier schon mal ein erster Screenshot von der Anwendung im Design-Modus:

Ein einfaches feed forward Netz ohne hidden Schicht:

Events als Commands ins ViewModel durchleiten

Es ist ein relativ bekanntes Problem, die von manchen WPF Controls ausgelösten Events in Commands umzuwandeln, die ans View Model gebunden werden können. Wenn man zum Beispiel ein KeyDown Ereignis behandeln will muss man normalerweise das normalerweise immer in der Code-Behind Datei tun, es sei denn man überlegt sich eine Methode, wie man das Event in einen Command gewandelt bekommt. Ein Ansatz für solche Umwandlungen eröffnet sich mit der System.Windows.Interactivity.dll, die uns erlaubt sogenannte Behaviors zu definieren. Interessant ist hier die TriggerAction Klasse, die als Reaktion auf Events ausgeführt werden kann. Die Implementierung sieht dann so aus:

public class CommandExecuteAction : TriggerAction<DependencyObject>
{
    protected override void Invoke(object parameter)
    {
        if (this.Command != null)
        {
            if (this.Command.CanExecute(parameter))
            {
                this.Command.Execute(parameter);
            }
        }
    }

    public ICommand Command
    {
        get { return (ICommand)GetValue(CommandProperty); }
        set { SetValue(CommandProperty, value); }
    }

    public static readonly DependencyProperty CommandProperty =
        DependencyProperty.Register("Command", typeof(ICommand), typeof(CommandExecuteAction));
}

Und der Xaml – Code, der aus einem Event einen Command macht(Beispielsweise für das Hyperlink_RequestNavigate Event), wobei i = System.Windows.Interactivity und tAct mein eigener namespace mit der Trigger Action ist:

<Hyperlink NavigateUri="{Binding Url}">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="RequestNavigate">
            <tAct:CommandExecuteAction Command="{Binding RequestNavigateCommand}"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
    <TextBlock Text="{Binding Title}" TextWrapping="Wrap"/>
</Hyperlink>

Schwachstellen in der Entlib 5 – Unity Container im Unity Container führt zu Stack Overflow Exception

Was mich jetzt, nachdem ich so richtig schön dabei bin mit der Enterprise Library 5 eine Anwendung zu schreiben ziemlich nervt, ist die Dispose Struktur von Microsoft. Ich hab festgestellt, dass wenn ich im Unity Container den UnityServiceLocator registriere eine StackOverflowException beim Dispose Aufruf kommt. Das liegt ganz einfach daran, dass der Unity Container intern beim Dispose alle Elemente durchscannt, die IDisposable implementieren und deren Dispose Methode aufruft(ist klar, macht ja auch Sinn). Aber: Jetzt kommt der in die Dispose Methode vom ServiceLocator rein, der ruft(logischerweise) dann wieder die Dispose vom UnityContainer auf, und so weiter. Mein Code:

public class Bootstrapper : IDisposable
{
    private bool isDisposed;
    private IUnityContainer container;

    ~Bootstrapper()
    {
        this.Dispose(false);
    }

    public void Run()
    {
        this.container = new UnityContainer();

        ((UnityConfigurationSection)ConfigurationManager.GetSection("unity")).Configure(this.container);
        this.container.RegisterInstance<IServiceLocator>(new UnityServiceLocator(this.container));
    }

    public void Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }

    private void Dispose(bool disposing)
    {
        if (!this.isDisposed)
        {
            this.isDisposed = true;
            this.container.Dispose();
        }
    }
}

Das Problem wäre ganz einfach zu beheben wenn Microsoft im Code vom UnityContainer das Feld isDisposed gleich am Anfang der Dispose Mathode auf true setzen würde, dann käme eine solche Kettenreaktion überhaupt nicht zustande. Vielleicht merken sie´s ja noch. Aber wir müssen uns jetzt darum kümmern, dass sowas trotzdem funktioniert. Die Lösung ist sehr simpel. Im UnityContainer gibt es schon ewig die Möglichkeit einem Objekt ein anderes Verhalten zu verpassen, über die Klasse LifetimeManager. Die überschreibt das Standartverhalten mit den ganzen Dispose() aufrufen. Auf dem ServiceLocator brauchen wir ja auch nicht die Dispose() aufzurufen, weil der sowieso nur wieder die vom UnityContainer aufrufen würde, und die rufen wir ja schon auf. Also lassen wir die einfach weg indem wir den Code der bei Run ausgeführt wird in den Folgenden ändern:

public void Run()
{
    this.container = new UnityContainer();

    ((UnityConfigurationSection)ConfigurationManager.GetSection("unity")).Configure(this.container);
    this.container.RegisterInstance<IServiceLocator>(new UnityServiceLocator(this.container), new ExternallyControlledLifetimeManager());
}