KomputeDer GPU -Rechenrahmen für Cross -Anbieter -Grafikkarten (AMD, Qualcomm, Nvidia & Friends) |
Treten Sie den Discord & Community -Anrufen bei? Dokumentationsblog -Beitrag ⌨ Beispiele?
Im Folgenden finden Sie ein GPU -Multiplikationsbeispiel unter Verwendung der C ++ - und Python -Kompute -Schnittstellen.
Sie können sich der Zwietracht anschließen, um Fragen / Diskussionen zu eröffnen, ein GitHub -Problem zu eröffnen oder die Dokumentation zu lesen.
Die C ++ - Schnittstelle bietet einen niedrigen Zugriff auf die nativen Komponenten von Kompute und ermöglicht fortschrittliche Optimierungen sowie die Erweiterung der Komponenten.
void kompute ( const std::string& shader) {
// 1. Create Kompute Manager with default settings (device 0, first queue and no extensions)
kp::Manager mgr;
// 2. Create and initialise Kompute Tensors through manager
// Default tensor constructor simplifies creation of float values
auto tensorInA = mgr. tensor ({ 2 ., 2 ., 2 . });
auto tensorInB = mgr. tensor ({ 1 ., 2 ., 3 . });
// Explicit type constructor supports uint32, int32, double, float and bool
auto tensorOutA = mgr. tensorT < uint32_t >({ 0 , 0 , 0 });
auto tensorOutB = mgr. tensorT < uint32_t >({ 0 , 0 , 0 });
std::vector<std::shared_ptr<kp::Memory>> params = {tensorInA, tensorInB, tensorOutA, tensorOutB};
// 3. Create algorithm based on shader (supports buffers & push/spec constants)
kp::Workgroup workgroup ({ 3 , 1 , 1 });
std::vector< float > specConsts ({ 2 });
std::vector< float > pushConstsA ({ 2.0 });
std::vector< float > pushConstsB ({ 3.0 });
auto algorithm = mgr. algorithm (params,
// See documentation shader section for compileSource
compileSource (shader),
workgroup,
specConsts,
pushConstsA);
// 4. Run operation synchronously using sequence
mgr. sequence ()
-> record <kp::OpSyncDevice>(params)
-> record <kp::OpAlgoDispatch>(algorithm) // Binds default push consts
-> eval () // Evaluates the two recorded operations
-> record <kp::OpAlgoDispatch>(algorithm, pushConstsB) // Overrides push consts
-> eval (); // Evaluates only last recorded operation
// 5. Sync results from the GPU asynchronously
auto sq = mgr. sequence ();
sq-> evalAsync <kp::OpSyncLocal>(params);
// ... Do other work asynchronously whilst GPU finishes
sq-> evalAwait ();
// Prints the first output which is: { 4, 8, 12 }
for ( const float & elem : tensorOutA-> vector ()) std::cout << elem << " " ;
// Prints the second output which is: { 10, 10, 10 }
for ( const float & elem : tensorOutB-> vector ()) std::cout << elem << " " ;
} // Manages / releases all CPU and GPU memory resources
int main () {
// Define a raw string shader (or use the Kompute tools to compile to SPIRV / C++ header
// files). This shader shows some of the main components including constants, buffers, etc
std::string shader = ( R"(
#version 450
layout (local_size_x = 1) in;
// The input tensors bind index is relative to index in parameter passed
layout(set = 0, binding = 0) buffer buf_in_a { float in_a[]; };
layout(set = 0, binding = 1) buffer buf_in_b { float in_b[]; };
layout(set = 0, binding = 2) buffer buf_out_a { uint out_a[]; };
layout(set = 0, binding = 3) buffer buf_out_b { uint out_b[]; };
// Kompute supports push constants updated on dispatch
layout(push_constant) uniform PushConstants {
float val;
} push_const;
// Kompute also supports spec constants on initalization
layout(constant_id = 0) const float const_one = 0;
void main() {
uint index = gl_GlobalInvocationID.x;
out_a[index] += uint( in_a[index] * in_b[index] );
out_b[index] += uint( const_one * push_const.val );
}
)" );
// Run the function declared above with our raw string shader
kompute (shader);
}
Das Python -Paket bietet eine interaktive Schnittstelle auf hohem Niveau, die das Experimentieren ermöglicht und gleichzeitig hohe Leistung und schnelle Entwicklungsworkflows gewährleistet.
from . utils import compile_source # using util function from python/test/utils
def kompute ( shader ):
# 1. Create Kompute Manager with default settings (device 0, first queue and no extensions)
mgr = kp . Manager ()
# 2. Create and initialise Kompute Tensors through manager
# Default tensor constructor simplifies creation of float values
tensor_in_a = mgr . tensor ([ 2 , 2 , 2 ])
tensor_in_b = mgr . tensor ([ 1 , 2 , 3 ])
# Explicit type constructor supports uint32, int32, double, float and bool
tensor_out_a = mgr . tensor_t ( np . array ([ 0 , 0 , 0 ], dtype = np . uint32 ))
tensor_out_b = mgr . tensor_t ( np . array ([ 0 , 0 , 0 ], dtype = np . uint32 ))
assert ( t_data . data_type () == kp . DataTypes . uint )
params = [ tensor_in_a , tensor_in_b , tensor_out_a , tensor_out_b ]
# 3. Create algorithm based on shader (supports buffers & push/spec constants)
workgroup = ( 3 , 1 , 1 )
spec_consts = [ 2 ]
push_consts_a = [ 2 ]
push_consts_b = [ 3 ]
# See documentation shader section for compile_source
spirv = compile_source ( shader )
algo = mgr . algorithm ( params , spirv , workgroup , spec_consts , push_consts_a )
# 4. Run operation synchronously using sequence
( mgr . sequence ()
. record ( kp . OpTensorSyncDevice ( params ))
. record ( kp . OpAlgoDispatch ( algo )) # Binds default push consts provided
. eval () # evaluates the two recorded ops
. record ( kp . OpAlgoDispatch ( algo , push_consts_b )) # Overrides push consts
. eval ()) # evaluates only the last recorded op
# 5. Sync results from the GPU asynchronously
sq = mgr . sequence ()
sq . eval_async ( kp . OpTensorSyncLocal ( params ))
# ... Do other work asynchronously whilst GPU finishes
sq . eval_await ()
# Prints the first output which is: { 4, 8, 12 }
print ( tensor_out_a )
# Prints the first output which is: { 10, 10, 10 }
print ( tensor_out_b )
if __name__ == "__main__" :
# Define a raw string shader (or use the Kompute tools to compile to SPIRV / C++ header
# files). This shader shows some of the main components including constants, buffers, etc
shader = """
#version 450
layout (local_size_x = 1) in;
// The input tensors bind index is relative to index in parameter passed
layout(set = 0, binding = 0) buffer buf_in_a { float in_a[]; };
layout(set = 0, binding = 1) buffer buf_in_b { float in_b[]; };
layout(set = 0, binding = 2) buffer buf_out_a { uint out_a[]; };
layout(set = 0, binding = 3) buffer buf_out_b { uint out_b[]; };
// Kompute supports push constants updated on dispatch
layout(push_constant) uniform PushConstants {
float val;
} push_const;
// Kompute also supports spec constants on initalization
layout(constant_id = 0) const float const_one = 0;
void main() {
uint index = gl_GlobalInvocationID.x;
out_a[index] += uint( in_a[index] * in_b[index] );
out_b[index] += uint( const_one * push_const.val );
}
"""
kompute ( shader )Sie können die interaktiven Colab -Notizbücher ausprobieren, mit denen Sie eine kostenlose GPU verwenden können. Die verfügbaren Beispiele sind die folgenden Beispiele von Python und C ++:
Probieren Sie den interaktiven C ++ - Colab aus dem Blog -Beitrag aus | Probieren Sie den interaktiven Python Colab aus dem Blog -Beitrag |
Sie können sich auch die beiden folgenden Gespräche ansehen, die auf der Fosdem 2021 -Konferenz vorgestellt wurden.
Beide Videos verfügen über Zeitstempel, mit denen Sie zum relevantesten Abschnitt für Sie überspringen können. Das Intro & Motivations für beide ist fast gleich, sodass Sie zu den spezifischeren Inhalten überspringen können.
Sehen Sie sich das Video für C ++ enthusiasten an | Sehen Sie sich das Video für Python & Machine Learning -Enthusiasten an |
Die Kernarchitektur von Kompute enthält Folgendes:
Um eine vollständige Aufschlüsselung zu sehen, können Sie in der C ++ - Klassenreferenz weiter lesen.
| Vollständige Architektur | Vereinfachte Komponenten |
|---|---|
(Sehr winzig, überprüfen Sie das vollständige Referenzdiagramm in DOCS, um Einzelheiten zu erhalten.) |
Kompute bietet Flexibilität, um Operationen asynrchonisch durch VK :: Zäune auszuführen. Darüber hinaus ermöglicht Kompute eine explizite Zuteilung von Warteschlangen, die eine parallele Ausführung von Operationen in Warteschlangenfamilien ermöglichen.
Das folgende Bild bietet eine Intuition darüber, wie Kompute -Sequenzen verschiedenen Warteschlangen zugewiesen werden können, um die parallele Ausführung basierend auf Hardware zu ermöglichen. Sie können das praktische Beispiel sowie die detaillierte Dokumentationsseite sehen, die beschreibt, wie es mit einem NVIDIA 1650 als Beispiel funktioniert.
Kompute wurde optimiert, um in mobilen Umgebungen zu arbeiten. Das Build -System ermöglicht die dynamische Belastung der Vulkan Shared Library für Android -Umgebungen sowie eine funktionierende Android -NDK -Wrapper für die CPP -Header.
Für einen vollständigen Tauchgang können Sie den Blog-Beitrag "Aufladung Ihrer mobilen Apps mit On-Device-GPU-beschleunigten maschinellem Lernen" lesen. Sie können auch auf den End-to-End-Beispielcode im Repository zugreifen, der mit Android Studio ausgeführt werden kann. |
Neben dem C ++ - Core SDK können Sie auch das Python -Paket von Kompute verwenden, das dieselbe Kernfunktionalität aufdeckt und die Interoperabilität mit Python -Objekten wie Listen, Numpy -Arrays usw. unterstützt.
Die einzigen Abhängigkeiten sind Python 3.5+ und CMake 3.4.1+. Sie können Kompute über das Python PYPI -Paket mit dem folgenden Befehl installieren.
pip install kp
Sie können auch von Master Branch mit:
pip install git+git://github.com/KomputeProject/kompute.git@master
Weitere Informationen finden Sie in der Python -Paketdokumentation oder der Referenzdokumentation der Python -Klasse.
Das bereitgestellte Build -System verwendet cmake , wodurch Cross -Plattform -Builds ermöglicht werden.
Das Makefile auf der besten Ebene bietet eine Reihe optimierter Konfigurationen für die Entwicklung sowie den Docker -Image -Build. Sie können jedoch einen Build mit dem folgenden Befehl starten:
cmake -Bbuild
Sie können auch Kompute in Ihrem Repo mit add_subdirectory hinzufügen - der Android -Beispiel cmakelists.txt -Datei zeigt, wie dies erledigt werden würde.
Eine fortgeschrittenere Übersicht über die Build -Konfiguration finden Sie in der Deep Dive -Dokumentation des Build -Systems.
Wir schätzen PRs und Probleme. Wenn Sie einen Beitrag leisten möchten, versuchen Sie, das Tag "Gutes Erstausgabe" zu überprüfen, aber selbst die Verwendung von Kompute- und Meldungsproblemen ist ein großer Beitrag!
Wenn Sie mit Debug -Schichten ausführen möchten, können Sie sie mit dem Parameter KOMPUTE_ENV_DEBUG_LAYERS als:
export KOMPUTE_ENV_DEBUG_LAYERS="VK_LAYER_LUNARG_api_dump"
Um die Dokumentation zu aktualisieren, müssen Sie:
make push_docs_to_ghpages Das Ausführen der Unit -Tests wurde für Mitwirkende erheblich vereinfacht.
Die auf der CPU ausgeführten Tests und können mit der Befehlszeilenschnittstelle (https://github.com/nektos/act) ausgelöst werden - Sobald Sie die Befehlszeile installiert haben (und den Docker -Daemon starten), müssen Sie nur eingeben:
$ act
[Python Tests/python-tests] Start image=axsauze/kompute-builder:0.2
[C++ Tests/cpp-tests ] Start image=axsauze/kompute-builder:0.2
[C++ Tests/cpp-tests ] ? docker run image=axsauze/kompute-builder:0.2 entrypoint=["/usr/bin/tail" "-f" "/dev/null"] cmd=[]
[Python Tests/python-tests] ? docker run image=axsauze/kompute-builder:0.2 entrypoint=["/usr/bin/tail" "-f" "/dev/null"] cmd=[]
...
Das Repository enthält Unit -Tests für den C ++ - und den Python -Code und befindet sich im Ordner test/ und python/test .
Die Tests werden derzeit unter Verwendung von Github -Aktionen durch den CI durchgeführt. Es verwendet die Bilder in docker-builders/ .
Um die Hardwareanforderungen zu minimieren, können die Tests ohne GPU direkt in der CPU mit Swiftshader ausgeführt werden.
Weitere Informationen zur Einrichtung des CI und der Tests finden Sie in der Dokumentation zum Abschnitt CI, Docker und Tests.
Dieses Projekt begann, nachdem er gesehen hatte, dass viele neue und renommierte ML & DL -Projekte wie Pytorch, Tensorflow, Alibaba DNN, Tencent NCNN - unter anderem - entweder integriert haben oder versuchen, den Vulkan -SDK zu integrieren, um den mobilen (und Cross -Vendor) GPU -Unterstützung hinzuzufügen.
Das Vulkan SDK bietet eine großartige Schnittstelle mit niedriger Ebene, die für hochspezialisierte Optimierungen ermöglicht. Es ist jedoch mit Kosten für hochweit ausführliche Code mit 500-2000 Code -Zeilen erforderlich, um sogar Anwendungscode zu schreiben. Dies hat dazu geführt, dass jedes dieser Projekte dieselbe Grundlinie implementieren musste, um die nicht komputierten Merkmale des Vulkan SDK abstrahieren zu können. Diese große Menge an nicht standardisierter Kesselplatte kann zu begrenzten Wissenstransferen führen, eine höhere Wahrscheinlichkeit für ein einzigartige Rahmen-Implementierungsfehler usw.
Derzeit entwickeln wir Kompute, um die Vulkan SDK -Schnittstelle nicht zu verbergen (da sie unglaublich gut gestaltet ist), sondern sie mit einem direkten Fokus auf die GPU -Computerfunktionen des Vulkan SDK zu erweitern. Dieser Artikel bietet einen hohen Überblick über die Motivationen von Kompute sowie eine Reihe von praktischen Beispielen, die sowohl die GPU -Computing als auch die Core -Kompute -Architektur einführen.