Nvidia GPUs (CUDA) के साथ जावा का उपयोग करना


144

मैं एक व्यवसाय परियोजना पर काम कर रहा हूं जो जावा में किया जाता है, और इसे व्यावसायिक बाजारों की गणना करने के लिए बड़ी गणना शक्ति की आवश्यकता होती है। सरल गणित, लेकिन बड़ी मात्रा में डेटा के साथ।

हमने कुछ CUDA GPU को ऑर्डर करने का आदेश दिया है और चूंकि Java CUDA द्वारा समर्थित नहीं है, मैं सोच रहा हूं कि कहां से शुरू किया जाए। क्या मुझे जेएनआई इंटरफ़ेस बनाना चाहिए? क्या मुझे जेसीयूडीए का उपयोग करना चाहिए या अन्य तरीके हैं?

मेरे पास इस क्षेत्र का अनुभव नहीं है और मैं चाहूंगा कि अगर कोई मुझे किसी चीज के लिए निर्देशित कर सके तो मैं शोध और सीखना शुरू कर सकता हूं।


2
जीपीयू आपको विशिष्ट प्रकार की गणना-गहन समस्या को गति देने में मदद करेगा। हालाँकि यदि आपके पास भारी मात्रा में डेटा है, तो आपको IO बद्ध होने की अधिक संभावना है। अधिकांश संभावना GPUs समाधान नहीं हैं।
स्टेप कुक

1
"GPGPUs का उपयोग कर जावा प्रदर्शन बढ़ाने" -> arxiv.org/abs/1508.06791
BlackBear

4
एक खुले प्रश्न की तरह, मुझे खुशी है कि mods इसे बंद नहीं किया क्योंकि Marco13 से जवाब अविश्वसनीय रूप से उपयोगी है! एक विकी होना चाहिए IMHO
जिमलोहे

जवाबों:


442

सबसे पहले, आपको इस तथ्य के बारे में पता होना चाहिए कि CUDA स्वचालित रूप से कम्प्यूटेशन को तेज नहीं करेगा। एक तरफ, क्योंकि GPU प्रोग्रामिंग एक कला है, और यह बहुत ही सही हो सकता है, इसे सही करने के लिए बहुत चुनौतीपूर्ण है । दूसरी ओर, क्योंकि केवल कुछ प्रकार की संगणनाओं के लिए जीपीयू अच्छी तरह से अनुकूल हैं ।

यह भ्रामक लग सकता है, क्योंकि आप मूल रूप से GPU पर कुछ भी गणना कर सकते हैं । प्रमुख बिंदु, निश्चित रूप से, आप एक अच्छा स्पीडअप प्राप्त करेंगे या नहीं। यहां सबसे महत्वपूर्ण वर्गीकरण यह है कि क्या कोई समस्या कार्य समानांतर या डेटा समानांतर है । पहले एक को संदर्भित करता है, मोटे तौर पर समस्याओं के लिए, जहां कई धागे अपने स्वयं के कार्यों पर काम कर रहे हैं, कम या ज्यादा स्वतंत्र रूप से। दूसरा एक समस्याओं को संदर्भित करता है जहां कई धागे सभी एक ही कर रहे हैं - लेकिन डेटा के विभिन्न भागों पर।

उत्तरार्द्ध इस तरह की समस्या है कि जीपीयू अच्छे हैं: उनके पास कई कोर हैं, और सभी कोर ऐसा ही करते हैं, लेकिन इनपुट डेटा के विभिन्न हिस्सों पर काम करते हैं।

आपने उल्लेख किया है कि आपके पास "सरल गणित है लेकिन भारी मात्रा में डेटा है"। हालांकि यह पूरी तरह से डेटा-समानांतर समस्या की तरह लग सकता है और इस तरह यह एक GPU के लिए अच्छी तरह से अनुकूल था, इस पर विचार करने के लिए एक और पहलू है: सैद्धांतिक कम्प्यूटेशनल पावर (FLOPS, फ़्लोटिंग पॉइंट ऑपरेशंस प्रति सेकंड) के मामले में GPU हास्यास्पद रूप से तेज़ हैं। लेकिन वे अक्सर मेमोरी बैंडविड्थ से नीचे गिर जाते हैं।

इससे समस्याओं का एक और वर्गीकरण होता है। अर्थात् क्या समस्याएँ स्मृति बद्ध हैं या बाध्य बाध्य हैं

पहला एक समस्याओं को संदर्भित करता है जहां प्रत्येक डेटा तत्व के लिए किए जाने वाले निर्देशों की संख्या कम है। उदाहरण के लिए, एक समानांतर वेक्टर जोड़ पर विचार करें: आपको दो डेटा तत्वों को पढ़ना होगा , फिर एक एकल प्रदर्शन करना होगा, और फिर परिणाम वेक्टर में योग लिखना होगा। जीपीयू पर ऐसा करते समय आपको स्पीडअप दिखाई नहीं देगा, क्योंकि एकल जोड़ मेमोरी पढ़ने / लिखने के प्रयासों की भरपाई नहीं करता है।

दूसरा शब्द, "कंप्यूट बाउंड", उन समस्याओं को संदर्भित करता है जहां निर्देशों की संख्या मेमोरी रीड / राइट की संख्या की तुलना में अधिक है। उदाहरण के लिए, एक मैट्रिक्स गुणन पर विचार करें: जब मैट्रिक्स का आकार n होता है, तो निर्देशों की संख्या O (n ^ 3) होगी। इस मामले में, कोई भी उम्मीद कर सकता है कि GPU एक निश्चित मैट्रिक्स आकार में सीपीयू से बेहतर प्रदर्शन करेगा। एक और उदाहरण तब हो सकता है जब कई जटिल त्रिकोणमितीय संगणनाएँ (साइन / कोसाइन आदि) "कुछ" डेटा तत्वों पर की जाती हैं।

अंगूठे के एक नियम के रूप में: आप मान सकते हैं कि "मुख्य" जीपीयू मेमोरी से एक डेटा तत्व को पढ़ने / लिखने में लगभग 500 मिलियन की विलंबता है।

इसलिए, GPUs के प्रदर्शन के लिए एक और महत्वपूर्ण बिंदु डेटा स्थानीयता है : यदि आपको डेटा पढ़ना है या लिखना है (और ज्यादातर मामलों में, आपको; ;-)) करना होगा, तो आपको यह सुनिश्चित करना चाहिए कि डेटा उतना ही पास रखा जाए। GPU कोर के लिए संभव है। जीपीयू में कुछ मेमोरी क्षेत्र होते हैं ("स्थानीय मेमोरी" या "साझा मेमोरी" के रूप में संदर्भित) जो आमतौर पर केवल कुछ केबी आकार का होता है, लेकिन डेटा के लिए विशेष रूप से कुशल है जो एक संगणना में शामिल होने वाला है।

इसलिए इसे फिर से जोर देने के लिए: GPU प्रोग्रामिंग एक कला है, जो केवल CPU पर समानांतर प्रोग्रामिंग से संबंधित है। जावा में थ्रेड्स जैसी चीजें, जैसे कि सभी कंसिस्टेंसी इन्फ्रास्ट्रक्चर के साथ ThreadPoolExecutors, ForkJoinPoolsआदि यह धारणा दे सकते हैं कि आपको अपने काम को किसी तरह विभाजित करना होगा और इसे कई प्रोसेसर के बीच वितरित करना होगा। GPU पर, आप बहुत निचले स्तर पर चुनौतियों का सामना कर सकते हैं: व्यवसाय, रजिस्टर दबाव, साझा स्मृति दबाव, मेमोरी coalescing ... बस कुछ ही नाम करने के लिए।

हालाँकि, जब आपके पास हल करने के लिए डेटा-समानांतर, कंप्यूट-बाउंड समस्या है, तो GPU जाने का रास्ता है।


एक सामान्य टिप्पणी: आपका विशेष रूप से CUDA के लिए कहा गया है। लेकिन मैं दृढ़ता से आपको OpenCL पर एक नज़र डालने की सलाह दूंगा। इसके कई फायदे हैं। सबसे पहले, यह एक विक्रेता-स्वतंत्र, खुले उद्योग मानक है, और AMD, Apple, Intel और NVIDIA द्वारा OpenCL के कार्यान्वयन हैं। इसके अतिरिक्त, जावा दुनिया में ओपनसीएल के लिए बहुत व्यापक समर्थन है। एकमात्र मामला जहां मैं CUDA के लिए समझौता करूँगा, जब आप CUDA रनटाइम लाइब्रेरीज़ का उपयोग करना चाहते हैं, जैसे BLFT (मैट्रिक्स / वेक्टर ऑपरेशन) के लिए FFT या CUBLAS के लिए CUFFT। यद्यपि ओपनसीएल के लिए समान पुस्तकालय प्रदान करने के लिए दृष्टिकोण हैं, उन्हें सीधे जावा की ओर से उपयोग नहीं किया जा सकता है, जब तक कि आप इन पुस्तकालयों के लिए अपने स्वयं के जेएनआई बाइंडिंग नहीं बनाते हैं।


आपको यह सुनना भी दिलचस्प लग सकता है कि अक्टूबर 2012 में, OpenJDK हॉटस्पॉट समूह ने "सुमात्रा": http://openjdk.java.net/projects/sumatra/ परियोजना शुरू की । इस परियोजना का लक्ष्य JVM में सीधे JIT के समर्थन के साथ GPU सहायता प्रदान करना है । वर्तमान स्थिति और प्रथम परिणाम http://mail.openjdk.java.net/mailman/listinfo/sumatra-dev पर उनकी मेलिंग सूची में देखे जा सकते हैं


हालांकि, कुछ समय पहले, मैंने "जावा पर जीपीयू" से संबंधित कुछ संसाधनों को सामान्य रूप से एकत्र किया था। मैं इन्हें फिर से यहाँ प्रस्तुत करूँगा, किसी विशेष क्रम में नहीं।

( अस्वीकरण : मैं http://jcuda.org/ और http://jocl.org/ का लेखक हूं )

(बाइट) कोड अनुवाद और OpenCL कोड पीढ़ी:

https://github.com/aparapi/aparapi : एक ओपन-सोर्स लाइब्रेरी है जो AMD द्वारा सक्रिय रूप से बनाई और बनाई जाती है। एक विशेष "कर्नेल" वर्ग में, एक विशिष्ट विधि को ओवरराइड कर सकता है जिसे समानांतर में निष्पादित किया जाना चाहिए। इस विधि के बाइट कोड को रन-टाइम पर खुद के बाइटकोड रीडर का उपयोग करके लोड किया जाता है। कोड को OpenCL कोड में अनुवादित किया जाता है, जिसे बाद में OpenCL संकलक का उपयोग करके संकलित किया जाता है। परिणाम को फिर OpenCL डिवाइस पर निष्पादित किया जा सकता है, जो कि GPU या CPU हो सकता है। यदि OpenCL में संकलन संभव नहीं है (या OpenCL उपलब्ध नहीं है), तो थ्रेड पूल का उपयोग करते हुए, कोड को अभी भी समानांतर में निष्पादित किया जाएगा।

https://github.com/pcpratts/rootbeer1 : जावा के कुछ हिस्सों को CUDA कार्यक्रमों में परिवर्तित करने के लिए एक ओपन-सोर्स लाइब्रेरी। यह समर्पित इंटरफेस प्रदान करता है जो यह इंगित करने के लिए लागू किए जा सकते हैं कि एक निश्चित वर्ग को GPU पर निष्पादित किया जाना चाहिए। Aparapi के विपरीत, यह स्वचालित रूप से "प्रासंगिक" डेटा (यानी, ऑब्जेक्ट ग्राफ का पूरा प्रासंगिक हिस्सा!) एक प्रतिनिधित्व में प्रस्तुत करता है जो GPU के लिए उपयुक्त है।

https : // code। लाइब्रेरी को पीएचडी थीसिस के संदर्भ में विकसित किया गया था, जिसमें अनुवाद प्रक्रिया के बारे में गहन पृष्ठभूमि की जानकारी है।

https://github.com/ochafik/ScalaCL : OpenCL के लिए स्लैब बाइंडिंग। ओपनसीएल के साथ समानांतर में विशेष स्काला संग्रह को संसाधित करने की अनुमति देता है। संग्रह के तत्वों पर कहे जाने वाले फ़ंक्शंस सामान्य रूप से स्काला फ़ंक्शंस (कुछ सीमाओं के साथ) हो सकते हैं जो तब ओपनसीएल कर्नेल में अनुवादित होते हैं।

भाषा एक्सटेंशन

http://www.ateji.com/px/index.html : जावा के लिए एक भाषा विस्तार जो समानांतर निर्माण (जैसे छोरों के लिए समानांतर, ओपनएमपी शैली) की अनुमति देता है जो तब ओपनसीएल के साथ GPU पर निष्पादित होते हैं। दुर्भाग्य से, यह बहुत आशाजनक परियोजना नहीं रह गई है।

http://www.habanero.rice.edu/Publications.html (JCUDA): एक पुस्तकालय जो विशेष जावा कोड (जिसे JCUDA कोड कहा जाता है) को Java- और CUDA-C कोड में अनुवाद कर सकता है, जिसे बाद में संकलित और निष्पादित किया जा सकता है। GPU। हालाँकि, लाइब्रेरी सार्वजनिक रूप से उपलब्ध नहीं है।

https://www2.informatik.uni-erlangen.de/EN/research/JavaOpenMP/index.html : OpenMP के निर्माण के लिए जावा भाषा का विस्तार, CUDA बैकएंड के साथ

Java OpenCL / CUDA बाइंडिंग लाइब्रेरी

https://github.com/ochafik/JavaCL : जावा ओपनसीएल के लिए बाइंडिंग: एक ऑब्जेक्ट-ओरिएंटेड ओपनसीएल लाइब्रेरी, ऑटो-जेनरेट किए गए निम्न-स्तरीय बाइंडिंग पर आधारित है।

http://jogamp.org/jocl/www/ : OpenCL के लिए जावा बाइंडिंग: ऑटो-जनरेट किए गए निम्न-स्तरीय बाइंडिंग के आधार पर ऑब्जेक्ट-ओरिएंटेड OpenCL लाइब्रेरी

http://www.lwjgl.org/ : OpenCL के लिए जावा बाइंडिंग: ऑटो-जेनरेट किए गए निम्न-स्तरीय बाइंडिंग और ऑब्जेक्ट-ओरिएंटेड सुविधा वर्ग

http://jocl.org/ : OpenCL के लिए जावा बाइंडिंग: निम्न स्तर के बाइंडिंग जो मूल OpenCL API की 1: 1 मैपिंग हैं

http://jcuda.org/ : CUDA के लिए जावा बाइंडिंग: निम्न स्तर के बाइंडिंग जो मूल CUDA API की 1: 1 मैपिंग हैं

विविध

http://sourceforge.net/projects/jopencl/ : OpenCL के लिए जावा बाइंडिंग। 2010 के बाद से इसका रखरखाव नहीं किया जा रहा है

http://www.hoopoe-cloud.com/ : CUDA के लिए जावा बाइंडिंग। अब बनाए रखने के लिए नहीं लगता है



2 मैट्रिक्स जोड़ने और तीसरे मैट्रिक्स में परिणाम संग्रहीत करने के संचालन पर विचार करें। जब ओपनली के बिना सीपीयू पर म्यूटली पिरोया जाता है तो अड़चन हमेशा वह कदम होगी जिसमें जोड़ होता है। यह ऑपरेशन स्पष्ट रूप से डेटा समानांतर है। लेकिन हम कहते हैं कि हम यह नहीं जानते हैं कि यह पहले से बंधी हुई मेमोरी होगी या मेमोरी बाउंड। लागू करने में बहुत समय और संसाधन लगते हैं और फिर देखते हैं कि सीपीयू इस ऑपरेशन को करने में बहुत बेहतर है। तो फिर OpenCL कोड को लागू किए बिना यह पहले से कैसे पहचान करता है।
15

2
@Cool_Coder वास्तव में पहले से बताना मुश्किल है कि क्या (या कितना) एक निश्चित कार्य एक GPU कार्यान्वयन से लाभान्वित होगा। पहली आंत की भावना के लिए, किसी को शायद अलग-अलग उपयोग-मामलों के साथ कुछ अनुभव की आवश्यकता होती है (जो मैंने माना है कि वास्तव में भी नहीं है)। एक पहला कदम nvidia.com/object/cuda_showcase_html.html को देखने और यह देखने के लिए हो सकता है कि क्या कोई "समान" समस्या सूचीबद्ध है। (यह CUDA है, लेकिन यह वैचारिक रूप से OpenCL के इतना करीब है कि परिणाम अधिकांश मामलों में स्थानांतरित किए जा सकते हैं)। ज्यादातर मामलों में, स्पीडअप का भी उल्लेख किया गया है, और उनमें से कई के पास कागजात या यहां तक ​​कि कोड के लिंक भी हैं
मार्को

Aparapi के लिए +1 - जावा में ओपेंसल के साथ आरंभ करने के लिए इसका एक सरल तरीका है, और आपको सरल मामलों के लिए सीपीयू बनाम जीपीयू प्रदर्शन की आसानी से तुलना करने की अनुमति मिलती है। इसके अलावा, यह AMD द्वारा बनाए रखा है, लेकिन एनवीडिया कार्ड के साथ ठीक काम करता है।
स्टेप कुक

12
यह सबसे अच्छी प्रतिक्रियाओं में से एक है जिसे मैंने स्टैकऑवरफ्लो पर कभी देखा है। समय देने और प्रयास करने के लिए शुक्रिया!
विग्गीनाश

1
@AlexPunnen यह शायद टिप्पणियों के दायरे से परे है। जहाँ तक मुझे पता है, OpenCV के पास कुछ CUDA सहायता है, जैसे कि docs.opencv.org/2.4/modules/gpu/doc/introduction.htmlDeveloper.nvidia.com/npp कई छवि प्रसंस्करण दिनचर्या, जो काम किया जा सकता है है। और github.com/GPUOpen-ProfessionalCompute-Tools/HIP यूडीए के लिए एक "वैकल्पिक" हो सकता है। यह एक नया प्रश्न के रूप में पूछना संभव हो सकता है, लेकिन किसी को इसे ठीक से वाक्यांश करने के लिए सावधान रहना होगा, "राय आधारित" / "तीसरे पक्ष के पुस्तकालयों के लिए पूछना" के लिए
चढ़ाव


2

से अनुसंधान मैंने किया है, यदि आप NVIDIA GPUs लक्षित कर रहे हैं और अधिक CUDA का उपयोग करने का फैसला किया है OpenCL , मैं तीन तरीके जावा में CUDA एपीआई का उपयोग करने के लिए मिला।

  1. जेकुडा (या वैकल्पिक) - http://www.jcuda.org/ । यह उन समस्याओं के लिए सबसे अच्छा समाधान है जो मैं काम कर रहा हूं। CUBLAS जैसे कई पुस्तकालय JCuda में उपलब्ध हैं। कर्नेल अभी भी C में लिखे गए हैं।
  2. जेएनआई - जेएनआई इंटरफेस लिखने के लिए मेरा पसंदीदा नहीं है, लेकिन बहुत शक्तिशाली हैं और आपको कुछ भी करने की अनुमति देगा CUDA।
  3. JavaCPP - यह मूल रूप से आपको सीधे C कोड लिखे बिना जावा में JNI इंटरफ़ेस बनाने की सुविधा देता है। यहाँ एक उदाहरण है: जावा में काम करने वाले CUDA कोड को चलाने का सबसे आसान तरीका क्या है? कैसे CUDA जोर के साथ इस का उपयोग करने के लिए। मेरे लिए, ऐसा लगता है जैसे आप एक जेएनआई इंटरफ़ेस लिख सकते हैं।

ये सभी उत्तर मूल रूप से जावा में C / C ++ कोड का उपयोग करने के तरीके हैं। आपको अपने आप से पूछना चाहिए कि आपको जावा का उपयोग करने की आवश्यकता क्यों है और यदि आप इसके बजाय C / C ++ में नहीं कर सकते हैं।

यदि आप जावा को पसंद करते हैं और यह जानते हैं कि इसका उपयोग कैसे करना है और सभी पॉइंटर प्रबंधन के साथ काम नहीं करना चाहते हैं और क्या नहीं तो C / C ++ के साथ आता है तो JCuda शायद इसका जवाब है। दूसरी ओर, CUDA थ्रस्ट लाइब्रेरी और इसके जैसे अन्य पुस्तकालयों का उपयोग C / C ++ में बहुत सारे सूचक प्रबंधन करने के लिए किया जा सकता है और शायद आपको इसे देखना चाहिए।

यदि आप C / C ++ पसंद करते हैं और पॉइंटर प्रबंधन का बुरा नहीं मानते हैं, लेकिन जावा का उपयोग करने के लिए मजबूर करने के लिए अन्य बाधाएं हैं, तो JNI सबसे अच्छा तरीका हो सकता है। हालाँकि, यदि आपकी जेएनआई विधियाँ सिर्फ कर्नेल कमांड के लिए रैपर हो रही हैं, तो आप सिर्फ जेसीयूडा का उपयोग कर सकते हैं।

JCuda के लिए कुछ विकल्प हैं जैसे Cuda4J और रूट बीयर, लेकिन वे बनाए रखने के लिए प्रतीत नहीं होते हैं। जबकि लेखन के समय यह JCuda CUDA 10.1 का समर्थन करता है। जो कि CUDA SDK सबसे अद्यतित है।

इसके अतिरिक्त कुछ जावा पुस्तकालय भी हैं जो CUDA का उपयोग करते हैं, जैसे कि deeplearning4j और Hadoop, जो कि आप सीधे कर्नेल कोड लिखने की आवश्यकता के बिना जो देख रहे हैं वह करने में सक्षम हो सकते हैं। मैंने उन पर बहुत अधिक ध्यान नहीं दिया है।


1

Marco13 ने पहले से ही एक उत्कृष्ट जवाब दिया

यदि आप CUDA / OpenCL कर्नेल को लागू किए बिना GPU का उपयोग करने के तरीके के लिए खोज में हैं, तो मैं फिनमैथ-लिबड़ा-क्यूडा-एक्सटेंशन (फाइनमैथ-लिब-गपु-एक्सटेंशन) http: // finmath का संदर्भ जोड़ना चाहूंगा .net / finmath-lib-cuda-extension / (अस्वीकरण: मैं इस परियोजना का अनुचर हूं)।

परियोजना "वेक्टर कक्षाएं" का एक कार्यान्वयन प्रदान करती है, सटीक होने के लिए, एक इंटरफ़ेस RandomVariable, जिसे अंकगणितीय संचालन और वैक्टर पर कमी प्रदान करता है। सीपीयू और जीपीयू के लिए कार्यान्वयन हैं। एल्गोरिथम भेदभाव या सादे वैल्यूएशन का उपयोग करके कार्यान्वयन हैं।

GPU पर प्रदर्शन सुधार वर्तमान में छोटे हैं (लेकिन आकार 100.000 के वैक्टर के लिए आपको एक कारक> 10 प्रदर्शन सुधार मिल सकता है)। यह छोटे कर्नेल आकार के कारण है। यह भविष्य के संस्करण में सुधार करेगा।

GPU कार्यान्वयन JCuda और JOCL का उपयोग करता है और Nvidia और ATI GPU के लिए उपलब्ध है।

पुस्तकालय अपाचे 2.0 है और मावेन सेंट्रल के माध्यम से उपलब्ध है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.