F # Leistung im wissenschaftlichen Rechnen


72

Ich bin gespannt, wie die F # -Leistung mit der C ++ - Leistung verglichen wird. Ich habe eine ähnliche Frage in Bezug auf Java gestellt, und ich hatte den Eindruck, dass Java nicht für starkes Zahlenkalkulieren geeignet ist.

Ich habe gelesen, dass F # skalierbarer und leistungsfähiger sein soll, aber wie ist diese reale Leistung im Vergleich zu C ++? Spezifische Fragen zur aktuellen Implementierung sind:

  • Wie gut macht es Gleitkomma?
  • Erlaubt es Vektoranweisungen
  • Wie freundlich ist es, Compiler zu optimieren?
  • Wie groß ist der Speicherbedarf? Ermöglicht es eine fein abgestimmte Kontrolle über die Speicherlokalität?
  • Hat es Kapazität für verteilte Speicherprozessoren, zum Beispiel Cray?
  • Welche Funktionen können für die Computerwissenschaft von Interesse sein, wenn es um die Verarbeitung schwerer Zahlen geht?
  • Gibt es tatsächliche wissenschaftliche Computerimplementierungen, die diese verwenden?

Vielen Dank


Ich habe C ++ aus dem Titel entfernt, um es nicht konfrontativ zu machen. Ich möchte jedoch die Leistung in Bezug auf C ++ kennen (damit ich mich darauf beziehen kann)
Anycorn

Antworten:


40
  • F # führt die Gleitkommaberechnung so schnell durch, wie es die .NET CLR zulässt. Kein großer Unterschied zu C # oder anderen .NET-Sprachen.
  • F # erlaubt keine Vektoranweisungen an sich, aber wenn Ihre CLR eine API für diese hat, sollte F # keine Probleme damit haben. Siehe zum Beispiel Mono .
  • Soweit ich weiß, gibt es momentan nur einen F # -Compiler. Vielleicht sollte die Frage lauten: "Wie gut ist der F # -Compiler in Bezug auf die Optimierung?". Die Antwort lautet auf jeden Fall "möglicherweise so gut wie der C # -Compiler, wahrscheinlich im Moment etwas schlechter". Beachten Sie, dass sich F # von z. B. C # in seiner Unterstützung für Inlining zur Kompilierungszeit unterscheidet, was möglicherweise einen effizienteren Code ermöglicht, der auf Generika basiert.
  • Der Speicherbedarf von F # -Programmen ähnelt dem anderer .NET-Sprachen. Die Kontrolle über Zuweisung und Speicherbereinigung ist dieselbe wie in anderen .NET-Sprachen.
  • Ich weiß nichts über die Unterstützung für verteilten Speicher.
  • F # hat sehr schöne Grundelemente für den Umgang mit flachen Datenstrukturen, z. B. Arrays und Listen. Schauen Sie sich zum Beispiel den Inhalt des Array-Moduls an: map, map2, mapi, iter, fold, zip ... Arrays sind im wissenschaftlichen Rechnen aufgrund ihrer inhärent guten Eigenschaften der Speicherlokalität sehr beliebt.
  • Für wissenschaftliche Berechnungspakete mit F # möchten Sie vielleicht sehen, was Jon Harrop tut.

9
Ich möchte nur darauf hinweisen, dass die Frage F # gegen C ++ war und diese Antwort F # gegen C # ist und dass C ++ und C # verschiedene Sprachen sind.
Matthieu M.

64

Ich bin gespannt, wie die F # -Leistung mit der C ++ - Leistung verglichen wird.

Variiert stark je nach Anwendung. Wenn Sie in einem Multithread-Programm in großem Umfang ausgefeilte Datenstrukturen verwenden, ist F # wahrscheinlich ein großer Gewinn. Wenn Sie die meiste Zeit in engen numerischen Schleifen verbringen, die Arrays mutieren, ist C ++ möglicherweise 2-3 × schneller.

Fallstudie: Ray Tracer Mein Benchmark verwendet hier einen Baum für hierarchisches Keulen und numerischen Ray-Sphere-Schnittcode, um ein Ausgabebild zu generieren. Dieser Benchmark ist mehrere Jahre alt und der C ++ - Code wurde im Laufe der Jahre Dutzende Male verbessert und von Hunderttausenden von Menschen gelesen. Don Syme von Microsoft hat es geschafft, eine F # -Implementierung zu schreiben, die etwas schneller als der schnellste C ++ - Code ist, wenn sie mit MSVC kompiliert und mit OpenMP parallelisiert wird.

Ich habe gelesen, dass F # skalierbarer und leistungsfähiger sein soll, aber wie ist diese reale Leistung im Vergleich zu C ++?

Das Entwickeln von Code ist mit F # viel einfacher und schneller als mit C ++. Dies gilt sowohl für die Optimierung als auch für die Wartung. Wenn Sie mit der Optimierung eines Programms beginnen, führt der gleiche Aufwand zu viel größeren Leistungssteigerungen, wenn Sie F # anstelle von C ++ verwenden. F # ist jedoch eine übergeordnete Sprache und legt folglich eine niedrigere Obergrenze für die Leistung fest. Wenn Sie also unendlich viel Zeit für die Optimierung haben, sollten Sie theoretisch immer in der Lage sein, schnelleren Code in C ++ zu erstellen.

Dies ist genau der gleiche Vorteil, den C ++ gegenüber Fortran und Fortran gegenüber handgeschriebenen Assemblern hatte.

Fallstudie: QR-Zerlegung Dies ist eine grundlegende numerische Methode aus der linearen Algebra, die von Bibliotheken wie LAPACK bereitgestellt wird. Die Referenz-LAPACK-Implementierung umfasst 2.077 Zeilen Fortran. Ich habe eine F # -Implementierung in weniger als 80 Codezeilen geschrieben, die das gleiche Leistungsniveau erreicht. Die Referenzimplementierung ist jedoch nicht schnell: Vom Hersteller optimierte Implementierungen wie Intels Math Kernel Library (MKL) sind häufig zehnmal schneller. Bemerkenswerterweise konnte ich meinen F # -Code weit über die Leistung der Intel-Implementierung hinaus optimieren , die auf Intel-Hardware ausgeführt wird, während mein Code unter 150 Codezeilen und vollständig generisch gehalten wurde (er kann einfache und doppelte Genauigkeit sowie komplexe und sogar symbolische Matrizen verarbeiten!): Für große, dünne Matrizen ist mein F # -Code bis zu 3 × schneller als der Intel MKL.

Beachten Sie, dass die Moral dieser Fallstudie nicht darin besteht, dass Sie erwarten sollten, dass Ihre F # schneller ist als von Anbietern optimierte Bibliotheken, sondern dass selbst Experten wie Intel produktive Optimierungen auf hoher Ebene verpassen, wenn sie nur Sprachen auf niedrigerer Ebene verwenden. Ich vermute, Intels Experten für numerische Optimierung haben die Parallelität nicht vollständig ausgenutzt, weil ihre Tools sie extrem umständlich machen, während F # sie mühelos macht.

Wie gut macht es Gleitkomma?

Die Leistung ist ähnlich wie bei ANSI C, einige Funktionen (z. B. Rundungsmodi) sind in .NET jedoch nicht verfügbar.

Erlaubt es Vektoranweisungen

Nein.

Wie freundlich ist es, Compiler zu optimieren?

Diese Frage macht keinen Sinn: F # ist eine proprietäre .NET-Sprache von Microsoft mit einem einzigen Compiler.

Wie groß ist der Speicherbedarf?

Eine leere Anwendung verwendet hier 1,3 MB.

Ermöglicht es eine fein abgestimmte Kontrolle über die Speicherlokalität?

Besser als die meisten speichersicheren Sprachen, aber nicht so gut wie C. Beispielsweise können Sie beliebige Datenstrukturen in F # entpacken, indem Sie sie als "Strukturen" darstellen.

Hat es Kapazität für verteilte Speicherprozessoren, zum Beispiel Cray?

Kommt darauf an, was du mit "Kapazität für" meinst. Wenn Sie .NET auf diesem Cray ausführen können, können Sie die Nachrichtenübergabe in F # verwenden (genau wie in der nächsten Sprache), aber F # ist hauptsächlich für Desktop-Multicore-x86-Computer vorgesehen.

Welche Funktionen können für die Computerwissenschaft von Interesse sein, wenn es um die Verarbeitung schwerer Zahlen geht?

Speichersicherheit bedeutet, dass Sie keine Segmentierungsfehler und Zugriffsverletzungen erhalten. Die Unterstützung für Parallelität in .NET 4 ist gut. Die Möglichkeit, Code im laufenden Betrieb über die interaktive F # -Sitzung in Visual Studio 2010 auszuführen, ist für interaktives technisches Computing äußerst nützlich.

Gibt es tatsächliche wissenschaftliche Computerimplementierungen, die diese verwenden?

Unsere kommerziellen Produkte für das wissenschaftliche Rechnen in F # haben bereits Hunderte von Benutzern.

Ihre Fragestellung zeigt jedoch, dass Sie wissenschaftliches Rechnen als Hochleistungsrechnen (z. B. Cray) und nicht als interaktives technisches Rechnen (z. B. MATLAB, Mathematica) betrachten. F # ist für Letzteres vorgesehen.


In meinen früheren Kommentaren habe ich darüber nachgedacht, was Sie als Hochleistungsrechnen bezeichnen, nicht als interaktiv.
Duffymo

2
Sie haben nicht genau die F # -Implementierung gepostet, die MATLAB angeblich übertroffen hat :-)
ZXX

16
@ ZXX: Ich habe es verkauft.
JD

1
@ Jon Harrop 'Speicherort? Besser als die meisten speichersicheren Sprachen, aber nicht so gut wie C 'Welche Optionen für eine solche Lokalitätssteuerung gibt es für C, die in F # nicht verfügbar sind? Und ist das eine Sprach- oder Plattformbeschränkung? Danke
user492238

2
Dieser Beitrag ist voll von unbegründeten Behauptungen. Besonders fraglich ist die Idee, dass Sie mit F # auf einfache Weise leistungsfähigeren Code als C ++ erstellen können. Ich war ziemlich stark in F # involviert, einschließlich vieler PRs, um die Array-Funktionen höherer Ordnung zu beschleunigen, und ich kann Ihnen versichern, dass dies im Allgemeinen nicht der Fall ist. Dass der Schöpfer von F # in F # eine schnellere Sache erstellen kann als in C ++, spricht möglicherweise mehr für Ihre relativen Talente in jeder Sprache als für jede angeborene Eigenschaft von ihnen.
Jackott

44

Zusätzlich zu dem, was andere sagten, gibt es einen wichtigen Punkt bei F # und das ist Parallelität . Die Leistung von normalem F # -Code wird von CLR bestimmt, obwohl Sie möglicherweise LAPACK von F # verwenden oder native Aufrufe mit C ++ / CLI als Teil Ihres Projekts tätigen können.

Gut gestaltete Funktionsprogramme lassen sich jedoch in der Regel viel einfacher parallelisieren. Dies bedeutet, dass Sie mit Multi-Core-CPUs, die Ihnen auf jeden Fall zur Verfügung stehen, wenn Sie wissenschaftliches Rechnen betreiben, auf einfache Weise an Leistung gewinnen können. Hier sind einige relevante Links:

In Bezug auf verteiltes Rechnen können Sie jedes verteilte Rechenframework verwenden, das für die .NET-Plattform verfügbar ist. Es gibt ein MPI.NET-Projekt, das gut mit F # funktioniert, aber Sie können möglicherweise auch DryadLINQ verwenden, ein MSR-Projekt.


16

Wie bei allen Sprach- / Leistungsvergleichen hängt Ihr Kilometerstand stark davon ab, wie gut Sie codieren können.

F # ist eine Ableitung von OCaml. Ich war überrascht, als ich herausfand, dass OCaml in der Finanzwelt, in der die Leistung bei der Eingabe von Zahlen sehr wichtig ist, häufig verwendet wird. Ich war weiter überrascht, als ich herausfand, dass OCaml eine der schnelleren Sprachen ist und eine Leistung aufweist, die der der schnellsten C- und C ++ - Compiler entspricht.

F # basiert auf der CLR . In der CLR wird Code in einer Form von Bytecode ausgedrückt, der als Common Intermediate Language bezeichnet wird. Als solches profitiert es von den Optimierungsfunktionen der JIT und hat eine Leistung, die mit C # vergleichbar ist (aber nicht unbedingt mit C ++), wenn der Code gut geschrieben ist.

CIL-Code kann vor der Laufzeit in einem separaten Schritt mithilfe des Native Image Generator (NGEN) zu nativem Code kompiliert werden. Dies beschleunigt alle späteren Ausführungen der Software, da die CIL-zu-Native-Kompilierung nicht mehr erforderlich ist.

Eine zu berücksichtigende Sache ist, dass funktionale Sprachen wie F # von einem deklarativeren Programmierstil profitieren. In gewisser Weise spezifizieren Sie die Lösung in wichtigen Sprachen wie C ++ zu stark, was die Optimierungsfähigkeit des Compilers einschränkt. Ein deklarativerer Programmierstil kann dem Compiler theoretisch zusätzliche Möglichkeiten zur algorithmischen Optimierung bieten.


interessant. Meine Welt beschränkt sich etwas auf Fortran und C ++, aber dann versuche ich, meinen Horizont zu erweitern. Ich habe OCaml-Anwendungen in meinem Bereich nicht wirklich gesehen
Anycorn

@ Robert Harvey - Das habe ich auch über OCaml gehört. Blitzschnelle Leistung und kleiner Code.
Onorio Catenacci

F # ist jedoch in .NET implementiert und bedeutet, dass es einige seiner Probleme in Bezug auf Überspezifikation erbt. F # -Funktionen sind .NET-Methoden hinter den Kulissen, und diese werden garantiert in einer bestimmten Reihenfolge ausgeführt, da sie Nebenwirkungen haben können - auch wenn F # diese in 99% der Fälle nicht hat oder Sie sich nicht um ihre Reihenfolge kümmern ( zB Debugging / Logging-Anweisungen). Ich warne also davor, von F # zu viel Leistung zu erwarten - es ist schön; es kann schnell vernünftig sein - aber es gewinnt meistens an Kürze aufgrund seiner funktionalen Natur, nicht aufgrund seiner Optimierbarkeit.
Eamon Nerbonne

2
Richtig, wenn Sie Inline-Funktionen verwenden und nur nebenwirkungsfreie Operationen verwenden (dh kein .NET-Interop), kann es neu angeordnet werden. Unglücklicherweise kann , wie mit Reflektor, plain F # Funktionen überprüft werden werden kompiliert in .NET - Methoden. MS selbst sagt auf der MSDN-Seite zu Inline-Funktionen: "Sie sollten die Verwendung von Inline-Funktionen zur Optimierung vermeiden, es sei denn, Sie haben alle anderen Optimierungstechniken ausprobiert." Aber selbst wenn Sie dies tun, welche Optimierungen wird F # bewirken, die ein ähnlicher Code in C ++ (statische Inline) nicht vornehmen kann? Mit manueller Hilfe bin ich sicher, dass F # ein Schritt in die richtige Richtung ist - aber es ist kein Haskell.
Eamon Nerbonne

1
Ich versuche nicht zu sagen, dass es für F # in bestimmten Situationen unmöglich ist, bestimmte Vorteile zu haben, sondern dass die Leute nicht glauben sollten, dass diese Vorteile in irgendeiner Weise automatisch oder sogar immer erreichbar sind. Semantisch unterscheidet sich die Sprache nicht wesentlich von C # - selbst wenn Sie dazu ermutigt werden, Strukturen zu verwenden, die in einem lokalen Bereich nebenwirkungsfrei sind, und selbst wenn der korrekte Compiler diese Informationen besser verwendet als der aktuelle Compiler von C #. Ich sehe wirklich nicht, wie die Semantik von F # mehr neue Compileroptimierungen über beispielsweise C ++ ermöglicht. Kein
Wundermittel

9

Es hängt davon ab, welche Art von wissenschaftlichem Computing Sie betreiben.

Wenn Sie traditional heavy computingz. B. lineare Algebra oder verschiedene Optimierungen durchführen, sollten Sie Ihren Code nicht in das .NET-Framework einfügen, zumindest nicht für F # geeignet. Da dies auf Algorithmenebene erfolgt, müssen die meisten Algorithmen in einer zwingenden Sprache codiert werden, um eine gute Leistung in Bezug auf Laufzeit und Speichernutzung zu erzielen. Andere erwähnten parallel, ich muss sagen, es ist wahrscheinlich nutzlos, wenn Sie Low-Level-Sachen wie parallel eine SVD-Implementierung machen. Denn wenn Sie wissen, wie man eine SVD parallelisiert, werden Sie einfach keine Hochsprachen verwenden. Fortran, C oder modifiziertes C (z. B. Cilk ) sind Ihre Freunde.

Ein Großteil des heutigen wissenschaftlichen Rechnens ist jedoch nicht von dieser Art, was eine Art von Anwendungen auf hoher Ebene ist, z. B. statistisches Rechnen und Data Mining. Bei diesen Aufgaben gibt es neben einer linearen Algebra oder Optimierung auch viele Datenflüsse, E / A-Vorgänge, Vorbesetzungen, Grafiken usw. Für diese Aufgaben ist F # sehr leistungsfähig, da es prägnant, funktional, sicher und einfach zu handhaben ist parallel usw.

Wie andere bereits erwähnt haben, unterstützt .Net Platform Invoke gut. Tatsächlich verwenden einige Projekte in MS .Net und P / Invoke zusammen, um die Leistung am Flaschenhals zu verbessern.


"Auf der Ebene der Algorithmen müssen die meisten Algorithmen in einer zwingenden Sprache codiert sein, um eine gute Leistung in Bezug auf Laufzeit und Speichernutzung zu erzielen" [Zitat erforderlich]
Julia

2
Die Laufzeit dieser Algorithmen wird in Flops gemessen, Hochsprachen sind schwer zu messen. Die Speichernutzung ist auch schwer vorherzusagen, wo Sie in C und Fortran genau zählen können, wie viele Bytes Sie verwenden würden.
Yin Zhu

2
"Es ist einfacher, die Leistung durch Inspektion in einer imperativen Sprache herauszufinden" unterscheidet sich SEHR von "nur imperative Sprachen liefern eine gute Leistung". Und auch falsch. Effekte zweiter Ordnung wie die Cache-Kohärenz sind auf modernen Prozessoren so wichtig, dass Messalgorithmen in FLOPs wertlos sind. Zwischen einem FLOP-optimierten Algorithmus und einem lokalitätsoptimierten Algorithmus, der das 10-fache der FLOPs benötigte, gewinnt der lokalitätsoptimierte Algorithmus. Wiederholen Sie nach mir: Die FPU ist nicht mehr der Engpass.
Ben Voigt

7

Ich glaube nicht, dass Sie leider viele verlässliche Informationen finden werden. F # ist immer noch eine sehr neue Sprache. Selbst wenn es ideal für leistungsintensive Workloads geeignet wäre, gäbe es nicht so viele Personen mit bedeutender Erfahrung, über die man berichten könnte. Darüber hinaus ist die Leistung nur sehr schwer genau einzuschätzen, und Mikrobenchmarks sind schwer zu verallgemeinern. Selbst in C ++ können Sie dramatische Unterschiede zwischen Compilern feststellen. Fragen Sie sich, ob F # mit einem C ++ - Compiler oder mit der hypothetischen "bestmöglichen" ausführbaren C ++ - Datei konkurrenzfähig ist ?

In Bezug auf bestimmte Benchmarks gegen C ++ sind hier einige möglicherweise relevante Links: O'Caml vs. F #: QR-Zerlegung ; F # vs Unmanaged C ++ für parallele Zahlen . Beachten Sie, dass der Autor als Autor von F # -bezogenem Material und als Anbieter von F # -Werkzeugen ein begründetes Interesse am Erfolg von F # hat. Nehmen Sie diese Behauptungen daher mit einem Körnchen Salz.

Ich denke, man kann mit Sicherheit sagen, dass es einige Anwendungen geben wird, bei denen F # hinsichtlich der Ausführungszeit wettbewerbsfähig ist, und wahrscheinlich einige andere, bei denen dies nicht der Fall ist. F # benötigt in den meisten Fällen wahrscheinlich mehr Speicher. Natürlich wird die ultimative Leistung auch stark von den Fähigkeiten des Programmierers abhängen - ich denke, F # wird mit ziemlicher Sicherheit eine produktivere Sprache für einen mäßig kompetenten Programmierer sein. Darüber hinaus denke ich, dass die CLR unter Windows derzeit auf den meisten Betriebssystemen für die meisten Aufgaben eine bessere Leistung als Mono aufweist, was sich auch auf Ihre Entscheidungen auswirken kann. Da F # wahrscheinlich einfacher zu parallelisieren ist als C ++, hängt es natürlich auch von der Art der Hardware ab, auf der Sie ausgeführt werden möchten.

Letztendlich denke ich, dass die einzige Möglichkeit, diese Frage wirklich zu beantworten, darin besteht, F # - und C ++ - Code zu schreiben, der für die Art der Berechnungen repräsentativ ist, die Sie ausführen und vergleichen möchten.


3
Der f # -Compiler ist möglicherweise neu (und die Leistung des vom F # -Compiler dafür generierten Codes unbekannt), aber der funktionsorientierte Teil von F # ist alles andere als neu. Es kann ohne Änderungen (dies gilt nur für F #, die auf eine bestimmte Weise geschrieben wurden) als OCaml kompiliert werden, das es seit Jahrhunderten gibt. OCaml ist nachweislich eine sehr optimiererfreundliche Sprache (aufgrund der Unveränderlichkeit für eine). Wenn der Optimierer in der F # mit dem OCaml-Optimierer auf Augenhöhe ist, ist eine starke Zahlenkalkulation für die F #
Rune FS

8
@RuneFS - Um eine gute Leistung in O'Caml zu erzielen, müssen häufig übergeordnete Konstrukte nicht verwendet werden (siehe z. B. Abschnitt 3.3 von janestreetcapital.com/minsky_weeks-jfp_18.pdf ). Wenn es um die F # -Leistung in der realen Welt geht, bedeutet die Tatsache, dass die einzige aktuelle F # -Implementierung unter .NET (CLR oder Mono) ausgeführt wird, dass bestimmte Optimierungen möglicherweise nicht verfügbar sind. Ich bin ein großer F # -Fan und in Zukunft können weitere Optimierungen mehr Geschwindigkeit bieten, aber im Moment vermute ich, dass es viele Anwendungen gibt, in denen "optimaler" C ++ - Code den "optimalen" F # -Code übertreffen würde.
KVB

1
F # läuft schnell genug. Ich erwarte nicht, dass sich der Compiler drastisch verbessern kann. Die Sprache ist im Kern immer noch eine Sprache, die Nebenwirkungen zulässt und eine bestimmte Ausführungsreihenfolge garantiert. stark einschränkende Optimierung. zB unterscheidet let f x y = (expensive x |> g) ysich grundlegend von let f x = expensive x |> gin F #, obwohl sie in einer funktionalen Welt semantisch äquivalent sind.
Eamon Nerbonne

1
@Eamon - Es gibt sicherlich Herausforderungen. Ich denke jedoch, dass Ihre Position zu trostlos ist. Da F # auf der CLR ausgeführt wird, wirken sich Verbesserungen entweder am F # -Compiler selbst oder an der CLR-JIT auf die Leistung aus. Es gibt wahrscheinlich viele Orte , wo der .NET JIT - Compiler kann dramatisch verbessert werden (zB Skipping eine größere Vielfalt an beweisbar unnötigen Feldgrenzen überprüft, inlining heuristische Verbesserungen, etc.). Angesichts der Tatsache, dass dies die erste Produktionsversion einer Sprache ist, die von einem kleinen Team erstellt wurde, wäre ich auch nicht überrascht, wenn weitere Anstrengungen die Ausgabe des F # -Compilers verbessern könnten.
KVB

1
Reinheitsanmerkungen könnten ein großer Gewinn für die Leistung sein. Und ich versuche nicht, F # herabzusetzen - es ist nur so, dass ich seine Vorteile eher auf der Seite der Code-Kürze und Lesbarkeit sehe, als dass ich viele Leistungsvorteile erwarte. Ich würde es vorziehen, wenn die Leute F # aus den Gründen wählen, die sie für besser halten - und sie dann verwerfen, wenn sie feststellen, dass dies selten der Fall ist. Zu neuen und verbesserten CLR-Optimierungen: Die CLR ist 10 Jahre alt. Es ist sicherlich nicht perfekt, aber ich würde nicht mehr mit radikalen Leistungsverbesserungen rechnen. Die offensichtlichen Verbesserungen wurden bereits vorgenommen.
Eamon Nerbonne

4

Hier sind zwei Beispiele, die ich teilen kann:

  1. Matrixmultiplikation: Ich habe einen Blog-Beitrag , in dem verschiedene Matrixmultiplikationsimplementierungen verglichen werden .

  2. LBFGS

Ich habe einen großen logistischen Regressionslöser mit LBFGS-Optimierung, der in C ++ codiert ist. Die Implementierung ist gut abgestimmt. Ich habe Code in C ++ / CLI in Code geändert, dh den Code in .Net kompiliert. Die .Net-Version ist drei- bis fünfmal langsamer als die naiv kompilierte Version für verschiedene Datensätze. Wenn Sie LBFGS in F # codieren, kann die Leistung nicht besser sein als C ++ / CLI oder C # (wäre aber sehr nahe).

Ich habe einen weiteren Beitrag über Warum F # die Sprache für Data Mining ist , obwohl es nicht ganz mit dem Leistungsproblem zusammenhängt, das Sie hier betreffen, sondern mit wissenschaftlichem Rechnen in F #.


3
-1: Dies ist nicht wahr: "Wenn Sie LBFGS in F # codieren, kann die Leistung nicht besser sein als C ++ / CLI oder C # (wäre aber sehr nahe)." Dies ist genau die Art von Anwendung, bei der F # viel schneller als C # sein kann.
JD

@ Jon Warum? Meinst du "parallel"?
Yin Zhu

1
@ Jon. Ich habe LBFGS codiert und kenne die Tricks zur Verbesserung der Leistung und der Speichernutzung, die im imperativen Stil codiert werden müssen. FP scheint hier gute Entwurfsmuster zu haben, aber die Leistung hat weniger mit Stil zu tun, insbesondere für hochoptimierten numerischen Code. Bei den meisten Problemen bei der Verwendung von LBFGS liegen die Zeitkosten hauptsächlich in den Funktionswert- und Gradientenberechnungen, alle paar werden in LBFGS selbst verwendet. Das Inline-Schalten erhöht die Leistung, wenn weit mehr LBFGS- oder Zeilensuchiterationen als die Berechnung des Funktionswerts und des Gradienten vorhanden sind. Dies ist jedoch im Allgemeinen nicht wahr.
Yin Zhu

1
Zweitens sehe ich kein Leistungsproblem, bei dem ein Vektor (ein Array-Zeiger) direkt an eine Funktion übergeben, ausgeführt und ein weiterer Zeiger auf das Gradienten-Array zurückgegeben wird. Inline hilft, wenn diese Funktion nur wenig Zeit kostet, wenn die Interaktion einen gewissen Aufwand verursacht. Da das Gradientenarray häufig sehr groß ist (aus diesem Grund benötigen wir Limitedmemory-BFGS), müssen wir sicherstellen, dass das Gradientenarray vorab zugewiesen und in zukünftigen Iterationen wiederverwendet wird. Nur viel zwingendes Denken bei der Implementierung in solchen Sachen.
Yin Zhu

3
Nein, der Hauptvorteil von inlineF # besteht nicht darin, dass der Overhead von Funktionsaufrufen entfällt, sondern dass die CLR Ihren Code typspezialisiert. Wenn Ihr LBFGS nur Handling float arrayoder vectorEin- und Ausgänge ist, haben Sie es von Hand auf einen bestimmten Fall spezialisiert, und das hat es viel weniger nützlich gemacht. Eine universelle BFGS-Implementierung sollte ihre Eingabe lesen und ihre Ausgabe direkt in die Datenstrukturen des Benutzers schreiben, wobei Funktionen verwendet werden, die der Benutzer bereitstellt. F # hat hier einen großen Leistungsvorteil gegenüber C #.
JD

3

Wenn ich "in 2-3 Jahren noch einmal fragen" sage, wird das Ihre Frage meiner Meinung nach vollständig beantworten :-)

Erwarten Sie zunächst nicht, dass sich F # in perfekter Weise von C # unterscheidet, es sei denn, Sie führen absichtlich einige verschlungene Rekursionen durch, und ich würde vermuten, dass dies nicht der Fall ist, da Sie nach Zahlen gefragt haben.

Gleitkomma-weise ist es sicherlich besser als Java, da CLR nicht auf plattformübergreifende Einheitlichkeit abzielt, was bedeutet, dass JIT auf 80 Bit geht, wann immer es kann. Auf der anderen Seite haben Sie keine Kontrolle darüber, außer die Anzahl der Variablen zu beobachten, um sicherzustellen, dass genügend FP-Register vorhanden sind.

Wenn Sie laut genug schreien, passiert in 2-3 Jahren möglicherweise etwas, da Direct3D ohnehin als allgemeine API in .NET eingeht und der in XNA erstellte C # -Code auf Xbox ausgeführt wird, der dem Bare Metal, das Sie mit CLR erhalten können, so nahe kommt . Das bedeutet immer noch, dass Sie selbst einen Zwischencode benötigen.

Erwarten Sie also nicht, dass CUDA oder sogar die Fähigkeit, NVIDIA-Bibliotheken zu verknüpfen und loszulegen. Sie hätten viel mehr Glück, wenn Sie diesen Ansatz mit Haskell versuchen würden, wenn Sie aus irgendeinem Grund wirklich eine "funktionale" Sprache benötigen, da Haskell so konzipiert wurde, dass es aus reiner Notwendigkeit verlinkungsfreundlich ist.

Mono.Simd wurde bereits erwähnt, und obwohl es für CLR wieder portierbar sein sollte, könnte es eine ziemliche Arbeit sein, dies tatsächlich zu tun.

Es gibt ziemlich viel Code in einem social.msdn-Beitrag über die Verwendung von SSE3 in .NET, mit C ++ / CLI und C #, Array-Blitting, Einfügen von SSE3-Code für Perf usw.

Es wurde darüber gesprochen, CECIL auf kompiliertem C # auszuführen , um Teile in HLSL zu extrahieren, in Shader zu kompilieren und einen Klebercode zu verknüpfen, um dies zu planen (CUDA macht sowieso das Äquivalent), aber ich glaube nicht, dass daraus etwas ausführbares wird.

Eine Sache, die Ihnen mehr wert sein könnte, wenn Sie bald etwas ausprobieren möchten, ist PhysX.Net auf Codeplex . Erwarten Sie nicht, dass es einfach auspackt und die Magie ausübt. Allerdings hat ih derzeit einen aktiven Autor und der Code ist sowohl normales C ++ als auch C ++ / CLI. Yopu kann wahrscheinlich Hilfe vom Autor erhalten, wenn Sie auf Details eingehen und möglicherweise einen ähnlichen Ansatz für CUDA verwenden möchten. Für CUDA mit voller Geschwindigkeit müssen Sie immer noch Ihre eigenen Kernel kompilieren und dann einfach eine Schnittstelle zu .NET herstellen. Je einfacher dieser Teil ist, desto glücklicher werden Sie sein.

Es gibt eine CUDA.NET-Bibliothek , die kostenlos sein soll, aber die Seite enthält nur eine E-Mail-Adresse. Erwarten Sie also einige angehängte Zeichenfolgen, und während der Autor einen Blog schreibt, ist er nicht besonders gesprächig darüber, was in der Bibliothek enthalten ist.

Oh, und wenn Sie das Budget haben, könnten Sie diesem Psi Lambda einen Blick geben (KappaCUDAnet ist der .NET-Teil). Anscheinend werden sie die Preise im November erhöhen (wenn es kein Verkaufstrick ist :-)


2
Die Optimierung von Musterübereinstimmungen ist ein Bereich, in dem F # das Potenzial hat, viel zu tun, C # jedoch nichts tut. Dies ist relevant für symbolische Berechnungen im wissenschaftlichen Rechnen. Nicht zufällig wurden einige der weltweit größten symbolischen Berechnungen in F #s Vorgänger OCaml geschrieben.
JD

2

Erstens ist C deutlich schneller als C ++. Wenn Sie also so viel Geschwindigkeit benötigen, sollten Sie die Bibliothek usw. in c erstellen.

In Bezug auf F # verwenden die meisten Benchmarks Mono, das teilweise aufgrund der Verwendung des Boehm-GC bis zu 2 * langsamer als MS CLR ist (sie haben einen neuen GC und LVVM, aber diese sind noch nicht ausgereift und unterstützen keine Generika usw.).

NEUE Sprachen selbst werden zu einem IR (CIL) kompiliert, das genauso effizient wie C ++ zu nativem Code kompiliert wird. Es gibt ein Problem, unter dem die meisten GC-Sprachen leiden, nämlich große Mengen veränderlicher Schreibvorgänge (dies schließt C ++ .NET ein, wie oben erwähnt). Und es gibt ein bestimmtes wissenschaftliches Problem, das dies erfordert. Diese sollten bei Bedarf wahrscheinlich eine native Bibliothek verwenden oder das Flyweight-Muster verwenden, um Objekte aus einem Pool wiederzuverwenden (wodurch Schreibvorgänge reduziert werden). Der Grund dafür ist, dass es in der .NET-CLR eine Schreibbarriere gibt, bei der beim Aktualisieren eines Referenzfelds (einschließlich eines Felds) in einer Tabelle ein Bit gesetzt wird, das besagt, dass diese Tabelle geändert wurde. Wenn Ihr Code aus vielen solchen Schreibvorgängen besteht, leidet er.

Das heißt, eine .NET-App wie C #, die viel statischen Code, Strukturen und Ref / Out für die Strukturen verwendet, kann eine C-ähnliche Leistung erzeugen, aber es ist sehr schwierig, so zu codieren oder den Code (wie C) zu pflegen.

Wo F # jedoch glänzt, ist Parralelismus über unveränderliche Daten, was mit mehr lesbasierten Problemen einhergeht. Es ist erwähnenswert, dass die meisten Benchmarks in veränderlichen Schreibvorgängen viel höher sind als in realen Anwendungen.

In Bezug auf Gleitkommazahlen sollten Sie eine alternative Bibliothek (dh die .Net-Bibliothek) zu den oCaml-Bibliotheken verwenden, da diese langsam ist. C / C ++ ermöglicht eine schnellere und niedrigere Genauigkeit, die oCaml standardmäßig nicht verwendet.

Zuletzt möchte ich argumentieren, dass eine Hochsprache wie C #, F # und eine ordnungsgemäße Profilerstellung für die gleiche Entwicklerzeit eine bessere Leistung als c und C ++ bieten. Wenn Sie einen Flaschenhals auf ac lib pinvoke call ändern, erhalten Sie auch eine C-ähnliche Leistung für kritische Bereiche. Das heißt, wenn Sie ein unbegrenztes Budget haben und mehr Wert auf Geschwindigkeit legen, ist Wartung der richtige Weg als C (nicht C ++).


1

Zuletzt wusste ich, dass die meisten wissenschaftlichen Berechnungen noch in FORTRAN durchgeführt wurden. Es ist immer noch schneller als alles andere für lineare Algebra-Probleme - nicht Java, nicht C, nicht C ++, nicht C #, nicht F #. LINPACK ist schön optimiert.

Die Bemerkung "Ihr Kilometerstand kann variieren" gilt jedoch für alle Benchmarks. Pauschalaussagen (außer meinen) sind selten wahr.


2
Entschuldigung, ich verstehe diesen Kommentar überhaupt nicht.
Duffymo

2
Die meisten von ihnen sind wegen der Trägheit immer noch fortran (ich glaube nicht, dass fortran heute einen großen Vorteil hat). Gleiches gilt für Linpack (das durch Lapack ersetzt wird). Einige neuere blas-Implementierungen wie atlas und goto sind eher C- und Plattform-Intrinsics als fortran.
Anycorn

1
Meine Daten sind datiert, gebe ich zu. Aber ich wäre daran interessiert, einen Benchmark zu sehen, der Fortran und C heute für die lineare Algebra vergleicht. Die große Schlüsselfrage: Welche Sprache verwenden Anbieter moderner kommerzieller Pakete?
Duffymo

das weiß ich nicht. Ich habe mir binäre Zeichenfolgen von mkl angesehen und das scheint eine Mischung aus C und fortran zu sein, mehr fortran. Ich hätte jedoch gedacht, dass es eine große handabgestimmte Baugruppe für Kernel geben würde. wäre in der Tat interessant zu wissen.
Anycorn

1
Unsere modernen kommerziellen Pakete für numerisches Rechnen sind in F # geschrieben und schlagen Fortran ziemlich glücklich. FFTW bietet die FFT-Routinen in MATLAB und ist in OCaml geschrieben und schlägt alles andere recht glücklich.
JD
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.