നിങ്ങളുടെ പൈത്തൺ കോഡിന്റെ പ്രകടനം പല മടങ്ങ് വർദ്ധിപ്പിക്കുക. ഈ സമഗ്രമായ ഗൈഡ് സിംഡ്, വെക്റ്ററൈസേഷൻ, നംപൈ, കൂടാതെ ആഗോള ഡെവലപ്പർമാർക്കുള്ള നൂതന ലൈബ്രറികളും പര്യവേക്ഷണം ചെയ്യുന്നു.
പ്രകടനം മെച്ചപ്പെടുത്താം: പൈത്തൺ സിംഡ്, വെക്റ്ററൈസേഷൻ എന്നിവയിലേക്കുള്ള ഒരു സമഗ്ര ഗൈഡ്
കമ്പ്യൂട്ടിംഗിൻ്റെ ലോകത്ത് വേഗത വളരെ പ്രധാനമാണ്. നിങ്ങൾ ഒരു ഡാറ്റാ സയൻ്റിസ്റ്റായി മെഷീൻ ലേണിംഗ് മോഡലിനെ പരിശീലിപ്പിക്കുകയാണെങ്കിലും, ഒരു സാമ്പത്തിക വിശകലന വിദഗ്ദ്ധനായി സിമുലേഷൻ നടത്തുകയാണെങ്കിലും, അല്ലെങ്കിൽ ഒരു സോഫ്റ്റ്വെയർ എഞ്ചിനീയറായി വലിയ ഡാറ്റാസെറ്റുകൾ പ്രോസസ്സ് ചെയ്യുകയാണെങ്കിലും, നിങ്ങളുടെ കോഡിൻ്റെ കാര്യക്ഷമത ഉൽപ്പാദനക്ഷമതയെയും വിഭവ ഉപഭോഗത്തെയും നേരിട്ട് ബാധിക്കുന്നു. ലാളിത്യത്തിനും വായനാക്ഷമതയ്ക്കും പേരുകേട്ട പൈത്തണിന് ഒരു പ്രധാന പോരായ്മയുണ്ട്: കമ്പ്യൂട്ടേഷണലി ഇന്റൻസീവ് ജോലികളിലെ പ്രകടനം, പ്രത്യേകിച്ച് ലൂപ്പുകൾ ഉൾപ്പെടുന്നവ. എന്നാൽ ഡാറ്റയുടെ ഓരോ എലമെൻ്റിനെയും ഒന്നിനുപുറകെ ഒന്നായി പ്രോസസ്സ് ചെയ്യുന്നതിനുപകരം, ഒരേസമയം ഒരു കൂട്ടം ഡാറ്റയിൽ പ്രവർത്തനങ്ങൾ നടത്താൻ കഴിഞ്ഞാലോ? സിംഡ് (SIMD) എന്ന സിപിയു ഫീച്ചർ നൽകുന്ന വെക്റ്ററൈസ്ഡ് കമ്പ്യൂട്ടേഷൻ എന്ന മാതൃകയുടെ വാഗ്ദാനമാണിത്.
ഈ ഗൈഡ് നിങ്ങളെ പൈത്തണിലെ സിംഗിൾ ഇൻസ്ട്രക്ഷൻ, മൾട്ടിപ്പിൾ ഡാറ്റ (സിംഡ്) പ്രവർത്തനങ്ങളുടെയും വെക്റ്ററൈസേഷൻ്റെയും ലോകത്തേക്ക് ആഴത്തിൽ കൊണ്ടുപോകും. സിപിയു ആർക്കിടെക്ചറിൻ്റെ അടിസ്ഥാന ആശയങ്ങൾ മുതൽ നംപൈ, നംബ, സൈത്തോൺ തുടങ്ങിയ ശക്തമായ ലൈബ്രറികളുടെ പ്രായോഗിക പ്രയോഗം വരെ നമ്മൾ യാത്ര ചെയ്യും. നിങ്ങളുടെ ഭൂമിശാസ്ത്രപരമായ സ്ഥാനമോ പശ്ചാത്തലമോ പരിഗണിക്കാതെ, നിങ്ങളുടെ വേഗത കുറഞ്ഞ, ലൂപ്പിംഗ് പൈത്തൺ കോഡിനെ ഉയർന്ന ഒപ്റ്റിമൈസ് ചെയ്തതും ഉയർന്ന പ്രകടനമുള്ളതുമായ ആപ്ലിക്കേഷനുകളാക്കി മാറ്റാനുള്ള അറിവ് നിങ്ങൾക്ക് നൽകുക എന്നതാണ് ഞങ്ങളുടെ ലക്ഷ്യം.
അടിത്തറ: സിപിയു ആർക്കിടെക്ചറും സിംഡും മനസ്സിലാക്കുന്നു
വെക്റ്ററൈസേഷൻ്റെ ശക്തി ശരിക്കും മനസ്സിലാക്കാൻ, ഒരു ആധുനിക സെൻട്രൽ പ്രോസസ്സിംഗ് യൂണിറ്റ് (സിപിയു) എങ്ങനെ പ്രവർത്തിക്കുന്നുവെന്ന് നമ്മൾ ആദ്യം പരിശോധിക്കണം. സിംഡിന്റെ മാന്ത്രികത ഒരു സോഫ്റ്റ്വെയർ തന്ത്രമല്ല; സംഖ്യാപരമായ കമ്പ്യൂട്ടിംഗിൽ വിപ്ലവം സൃഷ്ടിച്ച ഒരു ഹാർഡ്വെയർ കഴിവാണ് അത്.
SISD-യിൽ നിന്ന് SIMD-യിലേക്ക്: കമ്പ്യൂട്ടേഷനിലെ ഒരു മാതൃകാപരമായ മാറ്റം
വർഷങ്ങളോളം, കമ്പ്യൂട്ടേഷൻ്റെ പ്രധാന മാതൃക SISD (സിംഗിൾ ഇൻസ്ട്രക്ഷൻ, സിംഗിൾ ഡാറ്റ) ആയിരുന്നു. ഒരു പാചകക്കാരൻ ഓരോ പച്ചക്കറിയും ഓരോന്നായി ശ്രദ്ധാപൂർവ്വം മുറിക്കുന്നത് സങ്കൽപ്പിക്കുക. പാചകക്കാരന് ഒരു നിർദ്ദേശം ("മുറിക്കുക") ഉണ്ട്, അത് ഒരു ഡാറ്റയിൽ (ഒരു കാരറ്റ്) പ്രവർത്തിക്കുന്നു. ഇത് ഒരു പരമ്പരാഗത സിപിയു കോർ ഓരോ സൈക്കിളിലും ഒരു ഡാറ്റയിൽ ഒരു നിർദ്ദേശം നടപ്പിലാക്കുന്നതിന് തുല്യമാണ്. രണ്ട് ലിസ്റ്റുകളിൽ നിന്നുള്ള സംഖ്യകൾ ഓരോന്നായി കൂട്ടുന്ന ഒരു ലളിതമായ പൈത്തൺ ലൂപ്പ് SISD മോഡലിന് ഒരു മികച്ച ഉദാഹരണമാണ്:
# ആശയപരമായ SISD പ്രവർത്തനം
result = []
for i in range(len(list_a)):
# ഒരു സമയം ഒരു ഡാറ്റയിൽ (a[i], b[i]) ഒരു നിർദ്ദേശം (add)
result.append(list_a[i] + list_b[i])
ഈ സമീപനം ക്രമാനുഗതമാണ്, ഓരോ ആവർത്തനത്തിനും പൈത്തൺ ഇൻ്റർപ്രെട്ടറിൽ നിന്ന് കാര്യമായ ഓവർഹെഡ് ഉണ്ടാകുന്നു. ഇനി, ആ പാചകക്കാരന് ഒരു ലിവർ ഒറ്റത്തവണ വലിക്കുന്നതിലൂടെ ഒരേസമയം നാല് കാരറ്റുകളുടെ ഒരു നിര മുറിക്കാൻ കഴിയുന്ന ഒരു പ്രത്യേക യന്ത്രം നൽകുന്നത് സങ്കൽപ്പിക്കുക. ഇതാണ് SIMD (സിംഗിൾ ഇൻസ്ട്രക്ഷൻ, മൾട്ടിപ്പിൾ ഡാറ്റ)-യുടെ സത്ത. സിപിയു ഒരൊറ്റ നിർദ്ദേശം നൽകുന്നു, പക്ഷേ അത് ഒരു പ്രത്യേക, വീതിയുള്ള രജിസ്റ്ററിൽ ഒരുമിച്ച് പാക്ക് ചെയ്ത ഒന്നിലധികം ഡാറ്റാ പോയിൻ്റുകളിൽ പ്രവർത്തിക്കുന്നു.
ആധുനിക സിപിയുകളിൽ സിംഡ് എങ്ങനെ പ്രവർത്തിക്കുന്നു
ഇൻ്റൽ, എഎംഡി തുടങ്ങിയ നിർമ്മാതാക്കളിൽ നിന്നുള്ള ആധുനിക സിപിയുകളിൽ ഈ സമാന്തര പ്രവർത്തനങ്ങൾ നടത്താൻ പ്രത്യേക സിംഡ് രജിസ്റ്ററുകളും ഇൻസ്ട്രക്ഷൻ സെറ്റുകളും സജ്ജീകരിച്ചിരിക്കുന്നു. ഈ രജിസ്റ്ററുകൾ പൊതുവായ ഉദ്ദേശ്യമുള്ള രജിസ്റ്ററുകളേക്കാൾ വളരെ വിശാലമാണ്, അവയ്ക്ക് ഒരേസമയം ഒന്നിലധികം ഡാറ്റാ ഘടകങ്ങൾ ഉൾക്കൊള്ളാൻ കഴിയും.
- സിംഡ് രജിസ്റ്ററുകൾ: ഇവ സിപിയുവിലെ വലിയ ഹാർഡ്വെയർ രജിസ്റ്ററുകളാണ്. അവയുടെ വലുപ്പം കാലക്രമേണ വികസിച്ചു: 128-ബിറ്റ്, 256-ബിറ്റ്, ഇപ്പോൾ 512-ബിറ്റ് രജിസ്റ്ററുകൾ സാധാരണമാണ്. ഉദാഹരണത്തിന്, ഒരു 256-ബിറ്റ് രജിസ്റ്ററിന് എട്ട് 32-ബിറ്റ് ഫ്ലോട്ടിംഗ്-പോയിൻ്റ് നമ്പറുകളോ അല്ലെങ്കിൽ നാല് 64-ബിറ്റ് ഫ്ലോട്ടിംഗ്-പോയിൻ്റ് നമ്പറുകളോ ഉൾക്കൊള്ളാൻ കഴിയും.
- സിംഡ് ഇൻസ്ട്രക്ഷൻ സെറ്റുകൾ: സിപിയുകൾക്ക് ഈ രജിസ്റ്ററുകളിൽ പ്രവർത്തിക്കാൻ പ്രത്യേക നിർദ്ദേശങ്ങളുണ്ട്. നിങ്ങൾ ഈ ചുരുക്കെഴുത്തുകൾ കേട്ടിരിക്കാം:
- SSE (സ്ട്രീമിംഗ് സിംഡ് എക്സ്റ്റൻഷനുകൾ): ഒരു പഴയ 128-ബിറ്റ് ഇൻസ്ട്രക്ഷൻ സെറ്റ്.
- AVX (അഡ്വാൻസ്ഡ് വെക്റ്റർ എക്സ്റ്റൻഷനുകൾ): ഒരു 256-ബിറ്റ് ഇൻസ്ട്രക്ഷൻ സെറ്റ്, കാര്യമായ പ്രകടന മികവ് വാഗ്ദാനം ചെയ്യുന്നു.
- AVX2: കൂടുതൽ നിർദ്ദേശങ്ങളുള്ള AVX-ൻ്റെ ഒരു വിപുലീകരണം.
- AVX-512: പല ആധുനിക സെർവറുകളിലും ഉയർന്ന നിലവാരത്തിലുള്ള ഡെസ്ക്ടോപ്പ് സിപിയുകളിലും കാണുന്ന ശക്തമായ 512-ബിറ്റ് ഇൻസ്ട്രക്ഷൻ സെറ്റ്.
നമുക്ക് ഇത് ദൃശ്യവൽക്കരിക്കാം. `A = [1, 2, 3, 4]`, `B = [5, 6, 7, 8]` എന്നീ രണ്ട് അറേകൾ കൂട്ടിച്ചേർക്കണമെന്ന് കരുതുക, ഇവിടെ ഓരോ സംഖ്യയും 32-ബിറ്റ് ഇൻ്റിജറാണ്. 128-ബിറ്റ് സിംഡ് രജിസ്റ്ററുകളുള്ള ഒരു സിപിയുവിൽ:
- സിപിയു `[1, 2, 3, 4]` സിംഡ് രജിസ്റ്റർ 1-ലേക്ക് ലോഡ് ചെയ്യുന്നു.
- സിപിയു `[5, 6, 7, 8]` സിംഡ് രജിസ്റ്റർ 2-ലേക്ക് ലോഡ് ചെയ്യുന്നു.
- സിപിയു ഒരൊറ്റ വെക്റ്ററൈസ്ഡ് "add" നിർദ്ദേശം നടപ്പിലാക്കുന്നു (`_mm_add_epi32` ഒരു യഥാർത്ഥ നിർദ്ദേശത്തിൻ്റെ ഉദാഹരണമാണ്).
- ഒരൊറ്റ ക്ലോക്ക് സൈക്കിളിൽ, ഹാർഡ്വെയർ നാല് വ്യത്യസ്ത സങ്കലനങ്ങൾ സമാന്തരമായി നടത്തുന്നു: `1+5`, `2+6`, `3+7`, `4+8`.
- ഫലം, `[6, 8, 10, 12]`, മറ്റൊരു സിംഡ് രജിസ്റ്ററിൽ സംഭരിക്കുന്നു.
പ്രധാന കമ്പ്യൂട്ടേഷനിൽ SISD സമീപനത്തേക്കാൾ ഇത് 4 മടങ്ങ് വേഗത നൽകുന്നു, ഇൻസ്ട്രക്ഷൻ ഡിസ്പാച്ചിലെയും ലൂപ്പ് ഓവർഹെഡിലെയും വലിയ കുറവ് കണക്കിലെടുക്കാതെ തന്നെ.
പ്രകടനത്തിലെ വിടവ്: സ്കാലാർ വേഴ്സസ് വെക്റ്റർ പ്രവർത്തനങ്ങൾ
ഒരു പരമ്പരാഗത, ഒറ്റ-ഘടകം-ഒരു-സമയം എന്ന പ്രവർത്തനത്തിനുള്ള പദമാണ് സ്കാലാർ പ്രവർത്തനം. ഒരു മുഴുവൻ അറേയിലോ ഡാറ്റാ വെക്റ്ററിലോ ഉള്ള പ്രവർത്തനമാണ് വെക്റ്റർ പ്രവർത്തനം. പ്രകടനത്തിലെ വ്യത്യാസം സൂക്ഷ്മമല്ല; അത് പല മടങ്ങ് വലുതായിരിക്കും.
- കുറഞ്ഞ ഓവർഹെഡ്: പൈത്തണിൽ, ഒരു ലൂപ്പിൻ്റെ ഓരോ ആവർത്തനത്തിനും ഓവർഹെഡ് ഉണ്ട്: ലൂപ്പ് കണ്ടീഷൻ പരിശോധിക്കുക, കൗണ്ടർ വർദ്ധിപ്പിക്കുക, ഇൻ്റർപ്രെട്ടറിലൂടെ പ്രവർത്തനം ഡിസ്പാച്ച് ചെയ്യുക. ഒരു വെക്റ്റർ പ്രവർത്തനത്തിന് ഒരൊറ്റ ഡിസ്പാച്ച് മാത്രമേയുള്ളൂ, അറേയ്ക്ക് ആയിരമോ ദശലക്ഷമോ ഘടകങ്ങളുണ്ടെങ്കിലും.
- ഹാർഡ്വെയർ സമാന്തരം: നമ്മൾ കണ്ടതുപോലെ, സിംഡ് ഒരൊറ്റ സിപിയു കോറിനുള്ളിലെ സമാന്തര പ്രോസസ്സിംഗ് യൂണിറ്റുകളെ നേരിട്ട് ഉപയോഗിക്കുന്നു.
- മെച്ചപ്പെട്ട കാഷെ ലൊക്കാലിറ്റി: വെക്റ്ററൈസ്ഡ് പ്രവർത്തനങ്ങൾ സാധാരണയായി മെമ്മറിയുടെ തുടർച്ചയായ ബ്ലോക്കുകളിൽ നിന്നാണ് ഡാറ്റ വായിക്കുന്നത്. ഇത് സിപിയുവിൻ്റെ കാഷിംഗ് സിസ്റ്റത്തിന് വളരെ കാര്യക്ഷമമാണ്, കാരണം ഇത് തുടർച്ചയായ ഭാഗങ്ങളായി ഡാറ്റ മുൻകൂട്ടി ലഭ്യമാക്കാൻ രൂപകൽപ്പന ചെയ്തിട്ടുള്ളതാണ്. ലൂപ്പുകളിലെ റാൻഡം ആക്സസ് പാറ്റേണുകൾ പതിവായി "കാഷെ മിസ്സുകൾക്ക്" കാരണമാകും, അത് അവിശ്വസനീയമാംവിധം വേഗത കുറഞ്ഞതാണ്.
പൈത്തൺ ശൈലി: നംപൈ ഉപയോഗിച്ചുള്ള വെക്റ്ററൈസേഷൻ
ഹാർഡ്വെയർ മനസ്സിലാക്കുന്നത് കൗതുകകരമാണ്, പക്ഷേ അതിൻ്റെ ശക്തി പ്രയോജനപ്പെടുത്തുന്നതിന് നിങ്ങൾ ലോ-ലെവൽ അസംബ്ലി കോഡ് എഴുതേണ്ടതില്ല. പൈത്തൺ ഇക്കോസിസ്റ്റത്തിൽ വെക്റ്ററൈസേഷൻ ലളിതവും എളുപ്പവുമാക്കുന്ന ഒരു മികച്ച ലൈബ്രറിയുണ്ട്: നംപൈ.
നംപൈ: പൈത്തണിലെ ശാസ്ത്രീയ കമ്പ്യൂട്ടിംഗിൻ്റെ അടിസ്ഥാനം
പൈത്തണിലെ സംഖ്യാപരമായ കമ്പ്യൂട്ടേഷനുള്ള അടിസ്ഥാന പാക്കേജാണ് നംപൈ. അതിൻ്റെ പ്രധാന സവിശേഷത ശക്തമായ എൻ-ഡൈമൻഷണൽ അറേ ഒബ്ജക്റ്റായ `ndarray` ആണ്. നംപൈയുടെ യഥാർത്ഥ മാന്ത്രികത അതിൻ്റെ ഏറ്റവും പ്രധാനപ്പെട്ട റൂട്ടീനുകൾ (ഗണിതശാസ്ത്രപരമായ പ്രവർത്തനങ്ങൾ, അറേ മാനിപ്പുലേഷൻ, മുതലായവ) പൈത്തണിൽ എഴുതിയതല്ല എന്നതാണ്. അവ വളരെ ഒപ്റ്റിമൈസ് ചെയ്തതും മുൻകൂട്ടി കംപൈൽ ചെയ്തതുമായ C അല്ലെങ്കിൽ ഫോർട്രാൻ കോഡുകളാണ്, അവ BLAS (ബേസിക് ലീനിയർ ആൾജിബ്ര സബ്പ്രോഗ്രാമുകൾ), LAPACK (ലീനിയർ ആൾജിബ്ര പാക്കേജ്) പോലുള്ള ലോ-ലെവൽ ലൈബ്രറികളുമായി ബന്ധിപ്പിച്ചിരിക്കുന്നു. ഈ ലൈബ്രറികൾ പലപ്പോഴും ഹോസ്റ്റ് സിപിയുവിൽ ലഭ്യമായ സിംഡ് ഇൻസ്ട്രക്ഷൻ സെറ്റുകൾ ഏറ്റവും മികച്ച രീതിയിൽ ഉപയോഗിക്കുന്നതിനായി വെണ്ടർ-ട്യൂൺ ചെയ്തവയാണ്.
നംപൈയിൽ `C = A + B` എന്ന് നിങ്ങൾ എഴുതുമ്പോൾ, നിങ്ങൾ ഒരു പൈത്തൺ ലൂപ്പ് പ്രവർത്തിപ്പിക്കുകയല്ല. നിങ്ങൾ സിംഡ് നിർദ്ദേശങ്ങൾ ഉപയോഗിച്ച് സങ്കലനം നടത്തുന്ന ഉയർന്ന ഒപ്റ്റിമൈസ് ചെയ്ത ഒരു സി ഫംഗ്ഷനിലേക്ക് ഒരൊറ്റ കമാൻഡ് ഡിസ്പാച്ച് ചെയ്യുകയാണ്.
പ്രായോഗിക ഉദാഹരണം: പൈത്തൺ ലൂപ്പിൽ നിന്ന് നംപൈ അറേയിലേക്ക്
നമുക്കിത് പ്രവർത്തനത്തിൽ കാണാം. നമ്മൾ രണ്ട് വലിയ സംഖ്യകളുടെ അറേകൾ കൂട്ടിച്ചേർക്കാൻ പോകുന്നു, ആദ്യം ഒരു ശുദ്ധമായ പൈത്തൺ ലൂപ്പ് ഉപയോഗിച്ചും പിന്നീട് നംപൈ ഉപയോഗിച്ചും. നിങ്ങളുടെ സ്വന്തം മെഷീനിൽ ഫലങ്ങൾ കാണുന്നതിന് നിങ്ങൾക്ക് ഈ കോഡ് ഒരു ജൂപ്പിറ്റർ നോട്ട്ബുക്കിലോ പൈത്തൺ സ്ക്രിപ്റ്റിലോ പ്രവർത്തിപ്പിക്കാവുന്നതാണ്.
ആദ്യം, നമ്മൾ ഡാറ്റ സജ്ജീകരിക്കുന്നു:
import time
import numpy as np
# നമുക്ക് ധാരാളം ഘടകങ്ങൾ ഉപയോഗിക്കാം
num_elements = 10_000_000
# ശുദ്ധമായ പൈത്തൺ ലിസ്റ്റുകൾ
list_a = [i * 0.5 for i in range(num_elements)]
list_b = [i * 0.2 for i in range(num_elements)]
# നംപൈ അറേകൾ
array_a = np.arange(num_elements) * 0.5
array_b = np.arange(num_elements) * 0.2
ഇനി, നമുക്ക് ശുദ്ധമായ പൈത്തൺ ലൂപ്പിൻ്റെ സമയം അളക്കാം:
start_time = time.time()
result_list = [0] * num_elements
for i in range(num_elements):
result_list[i] = list_a[i] + list_b[i]
end_time = time.time()
python_duration = end_time - start_time
print(f"ശുദ്ധമായ പൈത്തൺ ലൂപ്പ് എടുത്ത സമയം: {python_duration:.6f} സെക്കൻഡ്")
ഇനി, തുല്യമായ നംപൈ പ്രവർത്തനം:
start_time = time.time()
result_array = array_a + array_b
end_time = time.time()
numpy_duration = end_time - start_time
print(f"നംപൈ വെക്റ്ററൈസ്ഡ് പ്രവർത്തനം എടുത്ത സമയം: {numpy_duration:.6f} സെക്കൻഡ്")
# വേഗതയിലുള്ള വർദ്ധനവ് കണക്കാക്കുക
if numpy_duration > 0:
print(f"നംപൈ ഏകദേശം {python_duration / numpy_duration:.2f}x വേഗതയേറിയതാണ്.")
ഒരു സാധാരണ ആധുനിക മെഷീനിൽ, ഔട്ട്പുട്ട് അമ്പരപ്പിക്കുന്നതായിരിക്കും. നംപൈ പതിപ്പ് 50 മുതൽ 200 മടങ്ങ് വരെ വേഗതയേറിയതായിരിക്കുമെന്ന് നിങ്ങൾക്ക് പ്രതീക്ഷിക്കാം. ഇത് ഒരു ചെറിയ ഒപ്റ്റിമൈസേഷനല്ല; കമ്പ്യൂട്ടേഷൻ എങ്ങനെ നടത്തുന്നു എന്നതിലെ ഒരു അടിസ്ഥാനപരമായ മാറ്റമാണിത്.
യൂണിവേഴ്സൽ ഫംഗ്ഷനുകൾ (ufuncs): നംപൈയുടെ വേഗതയുടെ എഞ്ചിൻ
നമ്മൾ ഇപ്പോൾ നടത്തിയ പ്രവർത്തനം (`+`) നംപൈയുടെ ഒരു യൂണിവേഴ്സൽ ഫംഗ്ഷൻ അഥവാ ufunc-ൻ്റെ ഉദാഹരണമാണ്. ഇവ `ndarray`-കളിൽ ഘടകം-ഘടകമായി പ്രവർത്തിക്കുന്ന ഫംഗ്ഷനുകളാണ്. നംപൈയുടെ വെക്റ്ററൈസ്ഡ് ശക്തിയുടെ കാതൽ ഇവയാണ്.
ufuncs-ൻ്റെ ഉദാഹരണങ്ങളിൽ ഇവ ഉൾപ്പെടുന്നു:
- ഗണിതശാസ്ത്രപരമായ പ്രവർത്തനങ്ങൾ: `np.add`, `np.subtract`, `np.multiply`, `np.divide`, `np.power`.
- ത്രികോണമിതി ഫംഗ്ഷനുകൾ: `np.sin`, `np.cos`, `np.tan`.
- ലോജിക്കൽ പ്രവർത്തനങ്ങൾ: `np.logical_and`, `np.logical_or`, `np.greater`.
- എക്സ്പോണൻഷ്യൽ, ലോഗരിഥമിക് ഫംഗ്ഷനുകൾ: `np.exp`, `np.log`.
ഒരു വ്യക്തമായ ലൂപ്പ് എഴുതാതെ തന്നെ സങ്കീർണ്ണമായ സൂത്രവാക്യങ്ങൾ പ്രകടിപ്പിക്കാൻ നിങ്ങൾക്ക് ഈ പ്രവർത്തനങ്ങൾ ഒരുമിച്ച് ബന്ധിപ്പിക്കാൻ കഴിയും. ഒരു ഗാസിയൻ ഫംഗ്ഷൻ കണക്കാക്കുന്നത് പരിഗണിക്കുക:
# x എന്നത് ഒരു ദശലക്ഷം പോയിൻ്റുകളുള്ള ഒരു നംപൈ അറേ ആണ്
x = np.linspace(-5, 5, 1_000_000)
# സ്കാലാർ സമീപനം (വളരെ വേഗത കുറഞ്ഞത്)
result = []
for val in x:
term = -0.5 * (val ** 2)
result.append((1 / np.sqrt(2 * np.pi)) * np.exp(term))
# വെക്റ്ററൈസ്ഡ് നംപൈ സമീപനം (അങ്ങേയറ്റം വേഗതയേറിയത്)
result_vectorized = (1 / np.sqrt(2 * np.pi)) * np.exp(-0.5 * x**2)
വെക്റ്ററൈസ്ഡ് പതിപ്പ് നാടകീയമായി വേഗതയേറിയത് മാത്രമല്ല, സംഖ്യാപരമായ കമ്പ്യൂട്ടിംഗിൽ പരിചയമുള്ളവർക്ക് കൂടുതൽ സംക്ഷിപ്തവും വായിക്കാൻ എളുപ്പവുമാണ്.
അടിസ്ഥാനങ്ങൾക്കപ്പുറം: ബ്രോഡ്കാസ്റ്റിംഗും മെമ്മറി ലേഔട്ടും
നംപൈയുടെ വെക്റ്ററൈസേഷൻ കഴിവുകൾ ബ്രോഡ്കാസ്റ്റിംഗ് എന്ന ഒരു ആശയം കൊണ്ട് കൂടുതൽ മെച്ചപ്പെടുത്തിയിരിക്കുന്നു. ഗണിതശാസ്ത്രപരമായ പ്രവർത്തനങ്ങൾക്കിടയിൽ വ്യത്യസ്ത രൂപങ്ങളുള്ള അറേകളെ നംപൈ എങ്ങനെ കൈകാര്യം ചെയ്യുന്നു എന്ന് ഇത് വിവരിക്കുന്നു. വലിയ അറേയുടെ ആകൃതിയുമായി പൊരുത്തപ്പെടുന്നതിന് ചെറിയ അറേയുടെ പകർപ്പുകൾ വ്യക്തമായി സൃഷ്ടിക്കാതെ തന്നെ ഒരു വലിയ അറേയ്ക്കും ഒരു ചെറിയ അറേയ്ക്കും (ഉദാഹരണത്തിന്, ഒരു സ്കാലാർ) ഇടയിൽ പ്രവർത്തനങ്ങൾ നടത്താൻ ബ്രോഡ്കാസ്റ്റിംഗ് നിങ്ങളെ അനുവദിക്കുന്നു. ഇത് മെമ്മറി ലാഭിക്കുകയും പ്രകടനം മെച്ചപ്പെടുത്തുകയും ചെയ്യുന്നു.
ഉദാഹരണത്തിന്, ഒരു അറേയിലെ ഓരോ ഘടകത്തെയും 10 കൊണ്ട് ഗുണിക്കാൻ, നിങ്ങൾ 10-കൾ നിറഞ്ഞ ഒരു അറേ സൃഷ്ടിക്കേണ്ടതില്ല. നിങ്ങൾ ലളിതമായി എഴുതുക:
my_array = np.array([1, 2, 3, 4])
scaled_array = my_array * 10 # സ്കാലാർ 10-നെ my_array-യിലുടനീളം ബ്രോഡ്കാസ്റ്റ് ചെയ്യുന്നു
കൂടാതെ, മെമ്മറിയിൽ ഡാറ്റ എങ്ങനെ ക്രമീകരിച്ചിരിക്കുന്നു എന്നത് നിർണായകമാണ്. നംപൈ അറേകൾ മെമ്മറിയുടെ ഒരു തുടർച്ചയായ ബ്ലോക്കിലാണ് സംഭരിക്കുന്നത്. സിംഡിന് ഇത് അത്യാവശ്യമാണ്, കാരണം ഡാറ്റ അതിൻ്റെ വിശാലമായ രജിസ്റ്ററുകളിലേക്ക് തുടർച്ചയായി ലോഡ് ചെയ്യേണ്ടതുണ്ട്. മെമ്മറി ലേഔട്ട് മനസ്സിലാക്കുന്നത് (ഉദാ. സി-സ്റ്റൈൽ റോ-മേജർ vs ഫോർട്രാൻ-സ്റ്റൈൽ കോളം-മേജർ) വിപുലമായ പ്രകടന ട്യൂണിംഗിന് പ്രധാനമാണ്, പ്രത്യേകിച്ചും മൾട്ടി-ഡൈമൻഷണൽ ഡാറ്റയുമായി പ്രവർത്തിക്കുമ്പോൾ.
അതിരുകൾ ഭേദിക്കുന്നു: നൂതന സിംഡ് ലൈബ്രറികൾ
പൈത്തണിലെ വെക്റ്ററൈസേഷനുള്ള ആദ്യത്തേതും ഏറ്റവും പ്രധാനപ്പെട്ടതുമായ ഉപകരണമാണ് നംപൈ. എന്നിരുന്നാലും, നിങ്ങളുടെ അൽഗോരിതം സാധാരണ നംപൈ ufuncs ഉപയോഗിച്ച് എളുപ്പത്തിൽ പ്രകടിപ്പിക്കാൻ കഴിയുന്നില്ലെങ്കിൽ എന്തുചെയ്യും? ഒരുപക്ഷേ നിങ്ങൾക്ക് സങ്കീർണ്ണമായ സോപാധിക യുക്തിയുള്ള ഒരു ലൂപ്പ് അല്ലെങ്കിൽ ഒരു ലൈബ്രറിയിലും ലഭ്യമല്ലാത്ത ഒരു കസ്റ്റം അൽഗോരിതം ഉണ്ടായിരിക്കാം. ഇവിടെയാണ് കൂടുതൽ നൂതനമായ ഉപകരണങ്ങൾ രംഗപ്രവേശം ചെയ്യുന്നത്.
നംബ: വേഗതയ്ക്കായി ജസ്റ്റ്-ഇൻ-ടൈം (JIT) കംപൈലേഷൻ
നംബ ഒരു ശ്രദ്ധേയമായ ലൈബ്രറിയാണ്, അത് ജസ്റ്റ്-ഇൻ-ടൈം (JIT) കംപൈലറായി പ്രവർത്തിക്കുന്നു. ഇത് നിങ്ങളുടെ പൈത്തൺ കോഡ് വായിക്കുകയും, റൺടൈമിൽ, പൈത്തൺ എൻവയോൺമെൻ്റിൽ നിന്ന് പുറത്തുപോകാതെ തന്നെ അതിനെ ഉയർന്ന ഒപ്റ്റിമൈസ് ചെയ്ത മെഷീൻ കോഡിലേക്ക് വിവർത്തനം ചെയ്യുകയും ചെയ്യുന്നു. സാധാരണ പൈത്തണിൻ്റെ പ്രധാന ദൗർബല്യമായ ലൂപ്പുകൾ ഒപ്റ്റിമൈസ് ചെയ്യുന്നതിൽ ഇത് പ്രത്യേകിച്ചും മികച്ചതാണ്.
നംബ ഉപയോഗിക്കുന്നതിനുള്ള ഏറ്റവും സാധാരണമായ മാർഗ്ഗം അതിൻ്റെ ഡെക്കറേറ്ററായ `@jit` വഴിയാണ്. നംപൈയിൽ വെക്റ്ററൈസ് ചെയ്യാൻ പ്രയാസമുള്ള ഒരു ഉദാഹരണം എടുക്കാം: ഒരു കസ്റ്റം സിമുലേഷൻ ലൂപ്പ്.
import numpy as np
from numba import jit
# നംപൈയിൽ വെക്റ്ററൈസ് ചെയ്യാൻ പ്രയാസമുള്ള ഒരു സാങ്കൽപ്പിക ഫംഗ്ഷൻ
def simulate_particles_python(positions, velocities, steps):
for _ in range(steps):
for i in range(len(positions)):
# ചില സങ്കീർണ്ണമായ, ഡാറ്റയെ ആശ്രയിച്ചുള്ള ലോജിക്
if positions[i] > 0:
velocities[i] -= 9.8 * 0.01
else:
velocities[i] = -velocities[i] * 0.9 # ഇലാസ്റ്റിക് അല്ലാത്ത കൂട്ടിയിടി
positions[i] += velocities[i] * 0.01
return positions
# അതേ ഫംഗ്ഷൻ തന്നെ, പക്ഷേ നംബ JIT ഡെക്കറേറ്ററോടുകൂടി
@jit(nopython=True, fastmath=True)
def simulate_particles_numba(positions, velocities, steps):
for _ in range(steps):
for i in range(len(positions)):
if positions[i] > 0:
velocities[i] -= 9.8 * 0.01
else:
velocities[i] = -velocities[i] * 0.9
positions[i] += velocities[i] * 0.01
return positions
`@jit(nopython=True)` ഡെക്കറേറ്റർ ചേർത്തുകൊണ്ട്, നിങ്ങൾ ഈ ഫംഗ്ഷനെ മെഷീൻ കോഡിലേക്ക് കംപൈൽ ചെയ്യാൻ നംബയോട് പറയുകയാണ്. `nopython=True` എന്ന ആർഗ്യുമെൻ്റ് നിർണായകമാണ്; വേഗത കുറഞ്ഞ പൈത്തൺ ഇൻ്റർപ്രെട്ടറിലേക്ക് തിരികെ പോകാത്ത കോഡ് നംബ ജനറേറ്റ് ചെയ്യുന്നുവെന്ന് ഇത് ഉറപ്പാക്കുന്നു. `fastmath=True` എന്ന ഫ്ലാഗ് കുറച്ചുകൂടി കൃത്യത കുറഞ്ഞതും എന്നാൽ വേഗതയേറിയതുമായ ഗണിതശാസ്ത്രപരമായ പ്രവർത്തനങ്ങൾ ഉപയോഗിക്കാൻ നംബയെ അനുവദിക്കുന്നു, ഇത് ഓട്ടോ-വെക്റ്ററൈസേഷൻ സാധ്യമാക്കും. നംബയുടെ കംപൈലർ ഇൻ്റർ ലൂപ്പ് വിശകലനം ചെയ്യുമ്പോൾ, സോപാധിക യുക്തിയുണ്ടെങ്കിൽ പോലും, ഒരേസമയം ഒന്നിലധികം കണികകളെ പ്രോസസ്സ് ചെയ്യുന്നതിന് സിംഡ് നിർദ്ദേശങ്ങൾ സ്വയമേവ ജനറേറ്റ് ചെയ്യാൻ അതിന് പലപ്പോഴും കഴിയും, ഇത് കൈകൊണ്ട് എഴുതിയ സി കോഡിന് തുല്യമോ അതിലും മികച്ചതോ ആയ പ്രകടനം നൽകുന്നു.
സൈത്തോൺ: പൈത്തണും സി/സി++-ഉം സംയോജിപ്പിക്കുന്നു
നംബ ജനപ്രിയമാകുന്നതിന് മുമ്പ്, പൈത്തൺ കോഡിൻ്റെ വേഗത വർദ്ധിപ്പിക്കുന്നതിനുള്ള പ്രധാന ഉപകരണം സൈത്തോൺ ആയിരുന്നു. സൈത്തോൺ പൈത്തൺ ഭാഷയുടെ ഒരു സൂപ്പർസെറ്റാണ്, അത് സി/സി++ ഫംഗ്ഷനുകളെ വിളിക്കുന്നതിനും വേരിയബിളുകളിലും ക്ലാസ് ആട്രിബ്യൂട്ടുകളിലും സി ടൈപ്പുകൾ പ്രഖ്യാപിക്കുന്നതിനും പിന്തുണയ്ക്കുന്നു. ഇത് ഒരു എഹെഡ്-ഓഫ്-ടൈം (AOT) കംപൈലറായി പ്രവർത്തിക്കുന്നു. നിങ്ങൾ നിങ്ങളുടെ കോഡ് ഒരു `.pyx` ഫയലിൽ എഴുതുന്നു, അത് സൈത്തോൺ ഒരു സി/സി++ സോഴ്സ് ഫയലിലേക്ക് കംപൈൽ ചെയ്യുന്നു, അത് പിന്നീട് ഒരു സ്റ്റാൻഡേർഡ് പൈത്തൺ എക്സ്റ്റൻഷൻ മൊഡ്യൂളിലേക്ക് കംപൈൽ ചെയ്യപ്പെടുന്നു.
സൈത്തോണിൻ്റെ പ്രധാന നേട്ടം അത് നൽകുന്ന സൂക്ഷ്മമായ നിയന്ത്രണമാണ്. സ്റ്റാറ്റിക് ടൈപ്പ് ഡിക്ലറേഷനുകൾ ചേർത്തുകൊണ്ട്, പൈത്തണിൻ്റെ ഡൈനാമിക് ഓവർഹെഡിൻ്റെ ഭൂരിഭാഗവും നിങ്ങൾക്ക് ഒഴിവാക്കാനാകും.
ഒരു ലളിതമായ സൈത്തോൺ ഫംഗ്ഷൻ ഇങ്ങനെയായിരിക്കാം:
# 'sum_module.pyx' എന്ന ഫയലിൽ
def sum_typed(long[:] arr):
cdef long total = 0
cdef int i
for i in range(arr.shape[0]):
total += arr[i]
return total
ഇവിടെ, സി-ലെവൽ വേരിയബിളുകൾ (`total`, `i`) പ്രഖ്യാപിക്കാൻ `cdef` ഉപയോഗിക്കുന്നു, കൂടാതെ `long[:]` ഇൻപുട്ട് അറേയുടെ ഒരു ടൈപ്പ് ചെയ്ത മെമ്മറി വ്യൂ നൽകുന്നു. ഇത് വളരെ കാര്യക്ഷമമായ ഒരു സി ലൂപ്പ് ജനറേറ്റ് ചെയ്യാൻ സൈത്തോണിനെ അനുവദിക്കുന്നു. വിദഗ്ദ്ധർക്ക്, സൈത്തോൺ സിംഡ് ഇൻട്രിൻസിക്സുകളെ നേരിട്ട് വിളിക്കാനുള്ള സംവിധാനങ്ങൾ പോലും നൽകുന്നു, ഇത് പ്രകടന-നിർണ്ണായക ആപ്ലിക്കേഷനുകൾക്ക് ആത്യന്തിക തലത്തിലുള്ള നിയന്ത്രണം വാഗ്ദാനം ചെയ്യുന്നു.
പ്രത്യേക ലൈബ്രറികൾ: ഇക്കോസിസ്റ്റത്തിലേക്കുള്ള ഒരു എത്തിനോട്ടം
ഉയർന്ന പ്രകടനമുള്ള പൈത്തൺ ഇക്കോസിസ്റ്റം വളരെ വലുതാണ്. നംപൈ, നംബ, സൈത്തോൺ എന്നിവയ്ക്കപ്പുറം മറ്റ് പ്രത്യേക ഉപകരണങ്ങളും നിലവിലുണ്ട്:
- NumExpr: വേഗതയേറിയ ഒരു ന്യൂമറിക്കൽ എക്സ്പ്രഷൻ ഇവാലുവേറ്റർ, മെമ്മറി ഉപയോഗം ഒപ്റ്റിമൈസ് ചെയ്തും `2*a + 3*b` പോലുള്ള എക്സ്പ്രഷനുകൾ വിലയിരുത്താൻ ഒന്നിലധികം കോറുകൾ ഉപയോഗിച്ചും ചിലപ്പോൾ നംപൈയെ മറികടക്കാൻ ഇതിന് കഴിയും.
- Pythran: ഒരു എഹെഡ്-ഓഫ്-ടൈം (AOT) കംപൈലർ, ഇത് പൈത്തൺ കോഡിൻ്റെ ഒരു ഉപവിഭാഗത്തെ, പ്രത്യേകിച്ച് നംപൈ ഉപയോഗിക്കുന്ന കോഡിനെ, ഉയർന്ന ഒപ്റ്റിമൈസ് ചെയ്ത C++11-ലേക്ക് വിവർത്തനം ചെയ്യുന്നു, ഇത് പലപ്പോഴും ശക്തമായ സിംഡ് വെക്റ്ററൈസേഷൻ സാധ്യമാക്കുന്നു.
- Taichi: ഉയർന്ന പ്രകടനമുള്ള പാരലൽ കമ്പ്യൂട്ടിംഗിനായി പൈത്തണിൽ ഉൾച്ചേർത്ത ഒരു ഡൊമെയ്ൻ-സ്പെസിഫിക് ലാംഗ്വേജ് (DSL), ഇത് കമ്പ്യൂട്ടർ ഗ്രാഫിക്സിലും ഫിസിക്സ് സിമുലേഷനുകളിലും പ്രത്യേകിച്ചും ജനപ്രിയമാണ്.
ആഗോള പ്രേക്ഷകർക്കുള്ള പ്രായോഗിക പരിഗണനകളും മികച്ച പരിശീലനങ്ങളും
ഉയർന്ന പ്രകടനമുള്ള കോഡ് എഴുതുന്നതിന് ശരിയായ ലൈബ്രറി ഉപയോഗിക്കുന്നതിനേക്കാൾ കൂടുതൽ കാര്യങ്ങൾ ഉൾപ്പെടുന്നു. സാർവത്രികമായി ബാധകമായ ചില മികച്ച രീതികൾ ഇവിടെയുണ്ട്.
സിംഡ് പിന്തുണ എങ്ങനെ പരിശോധിക്കാം
നിങ്ങൾക്ക് ലഭിക്കുന്ന പ്രകടനം നിങ്ങളുടെ കോഡ് പ്രവർത്തിക്കുന്ന ഹാർഡ്വെയറിനെ ആശ്രയിച്ചിരിക്കുന്നു. ഒരു സിപിയു ഏതൊക്കെ സിംഡ് ഇൻസ്ട്രക്ഷൻ സെറ്റുകളെ പിന്തുണയ്ക്കുന്നു എന്ന് അറിയുന്നത് പലപ്പോഴും ഉപയോഗപ്രദമാണ്. നിങ്ങൾക്ക് `py-cpuinfo` പോലുള്ള ഒരു ക്രോസ്-പ്ലാറ്റ്ഫോം ലൈബ്രറി ഉപയോഗിക്കാം.
# ഇത് ഉപയോഗിച്ച് ഇൻസ്റ്റാൾ ചെയ്യുക: pip install py-cpuinfo
import cpuinfo
info = cpuinfo.get_cpu_info()
supported_flags = info.get('flags', [])
print("സിംഡ് പിന്തുണ:")
if 'avx512f' in supported_flags:
print("- AVX-512 പിന്തുണയ്ക്കുന്നു")
elif 'avx2' in supported_flags:
print("- AVX2 പിന്തുണയ്ക്കുന്നു")
elif 'avx' in supported_flags:
print("- AVX പിന്തുണയ്ക്കുന്നു")
elif 'sse4_2' in supported_flags:
print("- SSE4.2 പിന്തുണയ്ക്കുന്നു")
else:
print("- അടിസ്ഥാന SSE പിന്തുണ അല്ലെങ്കിൽ പഴയത്.")
ഒരു ആഗോള പശ്ചാത്തലത്തിൽ ഇത് നിർണായകമാണ്, കാരണം ക്ലൗഡ് കമ്പ്യൂട്ടിംഗ് ഇൻസ്റ്റൻസുകളും ഉപയോക്തൃ ഹാർഡ്വെയറും വിവിധ പ്രദേശങ്ങളിൽ വ്യാപകമായി വ്യത്യാസപ്പെടാം. ഹാർഡ്വെയർ കഴിവുകൾ അറിയുന്നത് പ്രകടന സവിശേഷതകൾ മനസ്സിലാക്കാനോ അല്ലെങ്കിൽ പ്രത്യേക ഒപ്റ്റിമൈസേഷനുകൾ ഉപയോഗിച്ച് കോഡ് കംപൈൽ ചെയ്യാനോ സഹായിക്കും.
ഡാറ്റാ ടൈപ്പുകളുടെ പ്രാധാന്യം
സിംഡ് പ്രവർത്തനങ്ങൾ ഡാറ്റാ ടൈപ്പുകളുമായി (`dtype` ഇൻ നംപൈ) വളരെ പ്രത്യേകതയുള്ളതാണ്. നിങ്ങളുടെ സിംഡ് രജിസ്റ്ററിൻ്റെ വീതി നിശ്ചയിച്ചിരിക്കുന്നു. ഇതിനർത്ഥം നിങ്ങൾ ഒരു ചെറിയ ഡാറ്റാ ടൈപ്പ് ഉപയോഗിക്കുകയാണെങ്കിൽ, ഒരു രജിസ്റ്ററിൽ കൂടുതൽ ഘടകങ്ങൾ ഉൾക്കൊള്ളിക്കാനും ഓരോ നിർദ്ദേശത്തിനും കൂടുതൽ ഡാറ്റ പ്രോസസ്സ് ചെയ്യാനും കഴിയും.
ഉദാഹരണത്തിന്, ഒരു 256-ബിറ്റ് AVX രജിസ്റ്ററിന് ഇവ ഉൾക്കൊള്ളാൻ കഴിയും:
- നാല് 64-ബിറ്റ് ഫ്ലോട്ടിംഗ്-പോയിൻ്റ് നമ്പറുകൾ (`float64` അല്ലെങ്കിൽ `double`).
- എട്ട് 32-ബിറ്റ് ഫ്ലോട്ടിംഗ്-പോയിൻ്റ് നമ്പറുകൾ (`float32` അല്ലെങ്കിൽ `float`).
നിങ്ങളുടെ ആപ്ലിക്കേഷൻ്റെ കൃത്യത ആവശ്യകതകൾ 32-ബിറ്റ് ഫ്ലോട്ടുകൾക്ക് നിറവേറ്റാൻ കഴിയുമെങ്കിൽ, നിങ്ങളുടെ നംപൈ അറേകളുടെ `dtype` `np.float64`-ൽ നിന്ന് (പല സിസ്റ്റങ്ങളിലെയും ഡിഫോൾട്ട്) `np.float32`-ലേക്ക് മാറ്റുന്നത് AVX-പ്രാപ്തമാക്കിയ ഹാർഡ്വെയറിൽ നിങ്ങളുടെ കമ്പ്യൂട്ടേഷണൽ ത്രൂപുട്ട് ഇരട്ടിയാക്കാൻ സാധ്യതയുണ്ട്. നിങ്ങളുടെ പ്രശ്നത്തിന് മതിയായ കൃത്യത നൽകുന്ന ഏറ്റവും ചെറിയ ഡാറ്റാ ടൈപ്പ് എപ്പോഴും തിരഞ്ഞെടുക്കുക.
എപ്പോഴാണ് വെക്റ്ററൈസ് ചെയ്യേണ്ടാത്തത്
വെക്റ്ററൈസേഷൻ ഒരു ഒറ്റമൂലിയല്ല. ഇത് ഫലപ്രദമല്ലാത്തതോ അല്ലെങ്കിൽ വിപരീതഫലം ഉളവാക്കുന്നതോ ആയ സാഹചര്യങ്ങളുണ്ട്:
- ഡാറ്റയെ ആശ്രയിച്ചുള്ള കൺട്രോൾ ഫ്ലോ: പ്രവചനാതീതവും വിഭിന്നമായ എക്സിക്യൂഷൻ പാതകളിലേക്ക് നയിക്കുന്നതുമായ സങ്കീർണ്ണമായ `if-elif-else` ശാഖകളുള്ള ലൂപ്പുകൾ കംപൈലറുകൾക്ക് സ്വയമേവ വെക്റ്ററൈസ് ചെയ്യാൻ വളരെ പ്രയാസമാണ്.
- തുടർച്ചയായ ആശ്രിതത്വം: ഒരു ഘടകത്തിനായുള്ള കണക്കുകൂട്ടൽ മുൻ ഘടകത്തിൻ്റെ ഫലത്തെ ആശ്രയിച്ചിരിക്കുന്നുവെങ്കിൽ (ഉദാഹരണത്തിന്, ചില റിക്കർസീവ് ഫോർമുലകളിൽ), പ്രശ്നം സ്വാഭാവികമായും തുടർച്ചയായതാണ്, സിംഡ് ഉപയോഗിച്ച് സമാന്തരമാക്കാൻ കഴിയില്ല.
- ചെറിയ ഡാറ്റാസെറ്റുകൾ: വളരെ ചെറിയ അറേകൾക്ക് (ഉദാഹരണത്തിന്, ഒരു ഡസനിൽ താഴെ ഘടകങ്ങൾ), നംപൈയിലെ വെക്റ്ററൈസ്ഡ് ഫംഗ്ഷൻ കോൾ സജ്ജീകരിക്കുന്നതിൻ്റെ ഓവർഹെഡ് ലളിതവും നേരിട്ടുള്ളതുമായ പൈത്തൺ ലൂപ്പിൻ്റെ ചെലവിനേക്കാൾ കൂടുതലായിരിക്കും.
- ക്രമരഹിതമായ മെമ്മറി ആക്സസ്: നിങ്ങളുടെ അൽഗോരിതം പ്രവചനാതീതമായ രീതിയിൽ മെമ്മറിയിൽ ചാടേണ്ടതുണ്ടെങ്കിൽ, അത് സിപിയുവിൻ്റെ കാഷെ, പ്രീഫെച്ചിംഗ് സംവിധാനങ്ങളെ പരാജയപ്പെടുത്തും, ഇത് സിംഡിന്റെ ഒരു പ്രധാന നേട്ടം ഇല്ലാതാക്കും.
കേസ് സ്റ്റഡി: സിംഡ് ഉപയോഗിച്ചുള്ള ഇമേജ് പ്രോസസ്സിംഗ്
ഒരു പ്രായോഗിക ഉദാഹരണം ഉപയോഗിച്ച് ഈ ആശയങ്ങളെ നമുക്ക് ഉറപ്പിക്കാം: ഒരു കളർ ചിത്രം ഗ്രേസ്കെയിലിലേക്ക് മാറ്റുന്നത്. ഒരു ചിത്രം സംഖ്യകളുടെ ഒരു 3D അറേ മാത്രമാണ് (ഉയരം x വീതി x വർണ്ണ ചാനലുകൾ), ഇത് വെക്റ്ററൈസേഷന് അനുയോജ്യമായ ഒരു സ്ഥാനാർത്ഥിയാക്കുന്നു.
പ്രകാശതീവ്രതയ്ക്കുള്ള ഒരു സാധാരണ ഫോർമുല ഇതാണ്: `ഗ്രേസ്കെയിൽ = 0.299 * R + 0.587 * G + 0.114 * B`.
നമ്മുടെ പക്കൽ `(1920, 1080, 3)` ആകൃതിയിലും `uint8` ഡാറ്റാ ടൈപ്പിലുമുള്ള ഒരു നംപൈ അറേ ആയി ലോഡ് ചെയ്ത ഒരു ചിത്രം ഉണ്ടെന്ന് കരുതുക.
രീതി 1: ശുദ്ധമായ പൈത്തൺ ലൂപ്പ് (വേഗത കുറഞ്ഞ വഴി)
def to_grayscale_python(image):
h, w, _ = image.shape
grayscale_image = np.zeros((h, w), dtype=np.uint8)
for r in range(h):
for c in range(w):
pixel = image[r, c]
gray_value = 0.299 * pixel[0] + 0.587 * pixel[1] + 0.114 * pixel[2]
grayscale_image[r, c] = int(gray_value)
return grayscale_image
ഇതിൽ മൂന്ന് നെസ്റ്റഡ് ലൂപ്പുകൾ ഉൾപ്പെടുന്നു, ഉയർന്ന റെസല്യൂഷനുള്ള ഒരു ചിത്രത്തിന് ഇത് അവിശ്വസനീയമാംവിധം വേഗത കുറഞ്ഞതായിരിക്കും.
രീതി 2: നംപൈ വെക്റ്ററൈസേഷൻ (വേഗതയേറിയ വഴി)
def to_grayscale_numpy(image):
# R, G, B ചാനലുകൾക്കുള്ള വെയ്റ്റുകൾ നിർവചിക്കുക
weights = np.array([0.299, 0.587, 0.114])
# അവസാന അക്ഷത്തിൽ (വർണ്ണ ചാനലുകൾ) ഡോട്ട് പ്രോഡക്റ്റ് ഉപയോഗിക്കുക
grayscale_image = np.dot(image[...,:3], weights).astype(np.uint8)
return grayscale_image
ഈ പതിപ്പിൽ, നമ്മൾ ഒരു ഡോട്ട് പ്രോഡക്റ്റ് നടത്തുന്നു. നംപൈയുടെ `np.dot` വളരെ ഒപ്റ്റിമൈസ് ചെയ്തതാണ്, കൂടാതെ ഒരേസമയം നിരവധി പിക്സലുകൾക്കായി R, G, B മൂല്യങ്ങൾ ഗുണിക്കാനും കൂട്ടാനും സിംഡ് ഉപയോഗിക്കും. പ്രകടനത്തിലെ വ്യത്യാസം രാവും പകലും പോലെയായിരിക്കും - എളുപ്പത്തിൽ 100 മടങ്ങ് വേഗതയോ അതിൽ കൂടുതലോ.
ഭാവി: സിംഡും പൈത്തണിൻ്റെ വികസിച്ചുകൊണ്ടിരിക്കുന്ന ഭൂമികയും
ഉയർന്ന പ്രകടനമുള്ള പൈത്തണിൻ്റെ ലോകം നിരന്തരം വികസിച്ചുകൊണ്ടിരിക്കുകയാണ്. ഒന്നിലധികം ത്രെഡുകൾക്ക് പൈത്തൺ ബൈറ്റ്കോഡ് സമാന്തരമായി എക്സിക്യൂട്ട് ചെയ്യുന്നതിൽ നിന്ന് തടയുന്ന കുപ്രസിദ്ധമായ ഗ്ലോബൽ ഇൻ്റർപ്രെട്ടർ ലോക്ക് (GIL) വെല്ലുവിളിക്കപ്പെട്ടുകൊണ്ടിരിക്കുകയാണ്. GIL ഓപ്ഷണലാക്കാൻ ലക്ഷ്യമിടുന്ന പ്രോജക്റ്റുകൾ സമാന്തരത്വത്തിന് പുതിയ വഴികൾ തുറന്നേക്കാം. എന്നിരുന്നാലും, സിംഡ് ഒരു സബ്-കോർ തലത്തിലാണ് പ്രവർത്തിക്കുന്നത്, GIL അതിനെ ബാധിക്കുന്നില്ല, ഇത് വിശ്വസനീയവും ഭാവിയിൽ സുരക്ഷിതവുമായ ഒരു ഒപ്റ്റിമൈസേഷൻ തന്ത്രമാക്കി മാറ്റുന്നു.
ഹാർഡ്വെയർ കൂടുതൽ വൈവിധ്യപൂർണ്ണമാകുമ്പോൾ, പ്രത്യേക ആക്സിലറേറ്ററുകളും കൂടുതൽ ശക്തമായ വെക്റ്റർ യൂണിറ്റുകളും വരുമ്പോൾ, ഹാർഡ്വെയർ വിശദാംശങ്ങൾ മറച്ചുവെക്കുകയും അതേസമയം പ്രകടനം നൽകുകയും ചെയ്യുന്ന നംപൈ, നംബ പോലുള്ള ഉപകരണങ്ങൾ കൂടുതൽ നിർണായകമാകും. ഒരു സിപിയുവിനുള്ളിലെ സിംഡിൽ നിന്നുള്ള അടുത്ത ഘട്ടം പലപ്പോഴും ഒരു ജിപിയുവിലെ സിംറ്റ് (സിംഗിൾ ഇൻസ്ട്രക്ഷൻ, മൾട്ടിപ്പിൾ ത്രെഡുകൾ) ആണ്, കൂടാതെ CuPy (എൻവിഡിയ ജിപിയുകളിൽ നംപൈക്ക് പകരം വയ്ക്കാവുന്ന ഒന്ന്) പോലുള്ള ലൈബ്രറികൾ ഇതേ വെക്റ്ററൈസേഷൻ തത്വങ്ങൾ കൂടുതൽ വലിയ തോതിൽ പ്രയോഗിക്കുന്നു.
ഉപസംഹാരം: വെക്റ്ററിനെ ആശ്ലേഷിക്കുക
നമ്മൾ സിപിയുവിൻ്റെ കാതൽ മുതൽ പൈത്തണിൻ്റെ ഉയർന്ന തലത്തിലുള്ള അബ്സ്ട്രാക്ഷനുകൾ വരെ യാത്ര ചെയ്തു. പൈത്തണിൽ വേഗതയേറിയ ന്യൂമറിക്കൽ കോഡ് എഴുതാൻ, നിങ്ങൾ ലൂപ്പുകളിലല്ല, അറേകളിൽ ചിന്തിക്കണം എന്നതാണ് പ്രധാന പാഠം. ഇതാണ് വെക്റ്ററൈസേഷൻ്റെ സത്ത.
നമ്മുടെ യാത്രയുടെ സംഗ്രഹം:
- പ്രശ്നം: ഇൻ്റർപ്രെട്ടർ ഓവർഹെഡ് കാരണം ശുദ്ധമായ പൈത്തൺ ലൂപ്പുകൾ ന്യൂമറിക്കൽ ജോലികൾക്ക് വേഗത കുറഞ്ഞതാണ്.
- ഹാർഡ്വെയർ പരിഹാരം: ഒരേ പ്രവർത്തനം ഒരേസമയം ഒന്നിലധികം ഡാറ്റാ പോയിൻ്റുകളിൽ നടത്താൻ സിംഡ് ഒരൊറ്റ സിപിയു കോറിനെ അനുവദിക്കുന്നു.
- പ്രധാന പൈത്തൺ ഉപകരണം: വെക്റ്ററൈസേഷൻ്റെ അടിസ്ഥാന ശിലയാണ് നംപൈ, ഇത് ഒരു അവബോധജന്യമായ അറേ ഒബ്ജക്റ്റും ഒപ്റ്റിമൈസ് ചെയ്ത, സിംഡ്-പ്രാപ്തമാക്കിയ സി/ഫോർട്രാൻ കോഡായി എക്സിക്യൂട്ട് ചെയ്യുന്ന ufuncs-ൻ്റെ ഒരു സമ്പന്നമായ ലൈബ്രറിയും നൽകുന്നു.
- നൂതന ഉപകരണങ്ങൾ: നംപൈയിൽ എളുപ്പത്തിൽ പ്രകടിപ്പിക്കാൻ കഴിയാത്ത കസ്റ്റം അൽഗോരിതങ്ങൾക്കായി, നംബ നിങ്ങളുടെ ലൂപ്പുകൾ സ്വയമേവ ഒപ്റ്റിമൈസ് ചെയ്യുന്നതിന് JIT കംപൈലേഷൻ നൽകുന്നു, അതേസമയം സൈത്തോൺ പൈത്തണും സി-യും സംയോജിപ്പിച്ച് സൂക്ഷ്മമായ നിയന്ത്രണം നൽകുന്നു.
- മനോഭാവം: ഫലപ്രദമായ ഒപ്റ്റിമൈസേഷന് ഡാറ്റാ ടൈപ്പുകൾ, മെമ്മറി പാറ്റേണുകൾ എന്നിവ മനസ്സിലാക്കുകയും ജോലിക്കായി ശരിയായ ഉപകരണം തിരഞ്ഞെടുക്കുകയും ചെയ്യേണ്ടതുണ്ട്.
അടുത്ത തവണ നിങ്ങൾ ഒരു വലിയ സംഖ്യകളുടെ ലിസ്റ്റ് പ്രോസസ്സ് ചെയ്യുന്നതിനായി ഒരു `for` ലൂപ്പ് എഴുതുമ്പോൾ, ഒന്നു നിർത്തി ചോദിക്കുക: "എനിക്ക് ഇത് ഒരു വെക്റ്റർ പ്രവർത്തനമായി പ്രകടിപ്പിക്കാൻ കഴിയുമോ?" ഈ വെക്റ്ററൈസ്ഡ് ചിന്താഗതി സ്വീകരിക്കുന്നതിലൂടെ, നിങ്ങൾക്ക് ആധുനിക ഹാർഡ്വെയറിൻ്റെ യഥാർത്ഥ പ്രകടനം അൺലോക്ക് ചെയ്യാനും നിങ്ങളുടെ പൈത്തൺ ആപ്ലിക്കേഷനുകളെ വേഗതയുടെയും കാര്യക്ഷമതയുടെയും ഒരു പുതിയ തലത്തിലേക്ക് ഉയർത്താനും കഴിയും, നിങ്ങൾ ലോകത്ത് എവിടെയിരുന്ന് കോഡ് ചെയ്താലും.