যখন 2 ডি-অ্যারে (বা এনডি-অ্যারে) সি- বা এফ-সংলগ্ন হয়, তখন 2d-অ্যারেতে কোনও ফাংশন ম্যাপিংয়ের এই কার্যটি কার্যত 1 ডি-অ্যারেতে কোনও ফাংশন ম্যাপিংয়ের মতোই হয় - আমরা কেবল এটি সেভাবে দেখতে হবে, যেমন মাধ্যমে np.ravel(A,'K')
।
1 ডি-অ্যারের সম্ভাব্য সমাধানটি এখানে উদাহরণস্বরূপ আলোচনা করা হয়েছে ।
যাইহোক, যখন 2 ডি-অ্যারের স্মৃতিটি সংক্ষিপ্ত নয়, তখন পরিস্থিতিটি খানিকটা জটিল হয়, কারণ যদি অক্ষকে ভুল ক্রমে পরিচালনা করা হয় তবে কেউ সম্ভাব্য ক্যাশে মিস করা এড়াতে চান।
সেরা সম্ভাব্য ক্রমে অক্ষগুলি প্রক্রিয়া করার জন্য নম্পির কাছে ইতিমধ্যে একটি যন্ত্রপাতি রয়েছে। এই যন্ত্রপাতি ব্যবহার করার একটি সম্ভাবনা হ'ল np.vectorize
। তবে নম্পির ডকুমেন্টেশনে np.vectorize
বলা হয়েছে যে এটি "প্রাথমিকভাবে সুবিধার্থে সরবরাহ করা হয়, কার্য সম্পাদনের জন্য নয়" - একটি ধীর পাইথন ফাংশন পুরো সম্পর্কিত ওভারহেডের সাথে ধীর পাইথন ফাংশন স্থির রাখে! আর একটি সমস্যা হ'ল এর বিশাল স্মৃতি-খরচ consumption উদাহরণস্বরূপ দেখুন এই এসও-পোস্ট ।
যখন কেউ সি-ফাংশনটির পারফরম্যান্স পেতে চান তবে নম্পির যন্ত্রপাতি ব্যবহার করতে চান, তবে একটি ভাল সমাধান হ'ল ইউফঙ্কস তৈরির জন্য নাম্বার ব্যবহার করা, উদাহরণস্বরূপ:
# runtime generated C-function as ufunc
import numba as nb
@nb.vectorize(target="cpu")
def nb_vf(x):
return x+2*x*x+4*x*x*x
এটি সহজেই মারধর করে np.vectorize
তবে একই ফাংশনটি যখন নাম্পি-অ্যারে গুণ / সংযোজন হিসাবে সম্পাদিত হবে, অর্থাত্
# numpy-functionality
def f(x):
return x+2*x*x+4*x*x*x
# python-function as ufunc
import numpy as np
vf=np.vectorize(f)
vf.__name__="vf"
সময়-পরিমাপ-কোডের জন্য এই উত্তরের পরিশিষ্ট দেখুন:
নুম্বার সংস্করণ (সবুজ) পাইথন ফাংশন (অর্থাত্ np.vectorize
) এর চেয়ে প্রায় 100 গুণ বেশি গতিযুক্ত , এটি অবাক হওয়ার মতো নয়। তবে এটি নম্পি-কার্যকারিতা থেকে প্রায় 10 গুণ বেশি গতিযুক্ত, কারণ নম্বাস সংস্করণটির মধ্যবর্তী অ্যারেগুলির প্রয়োজন নেই এবং এইভাবে আরও দক্ষতার সাথে ক্যাশে ব্যবহার করা হয়।
যদিও নাম্বার ইউফুঙ্ক পদ্ধতিটি ব্যবহারযোগ্যতা এবং পারফরম্যান্সের মধ্যে একটি ভাল বাণিজ্য-বন্ধ, এটি এখনও আমরা করতে পারি না সেরা। তবুও কোনও কাজের জন্য সিলভার বুলেট বা কোনও পদ্ধতির সর্বোত্তম উপায় নেই - একটি সীমাবদ্ধতা কী এবং কীভাবে সেগুলি প্রশমিত করা যায় তা বুঝতে হবে।
উদাহরণস্বরূপ, তুরীয় কাজকর্মের জন্য (যেমন exp
, sin
, cos
) numba কোনো সুফল উপর উপলব্ধ করা হয় না numpy এর np.exp
(কোন অস্থায়ী নির্মিত অ্যারে রয়েছে - গতি-আপ এর প্রধান উৎস)। যাইহোক, আমার অ্যানাকোন্ডা ইনস্টলেশন 8192 এর চেয়ে বড় ভেক্টরগুলির জন্য ইন্টেলের ভিএমএল ব্যবহার করে - মেমরিটি সংক্ষিপ্ত না হলে এটি এটি করতে পারে না। সুতরাং ইন্টেলের ভিএমএল ব্যবহার করতে সক্ষম হওয়ার জন্য উপাদানগুলিকে একটি স্বতন্ত্র স্মৃতিতে অনুলিপি করা ভাল be
import numba as nb
@nb.vectorize(target="cpu")
def nb_vexp(x):
return np.exp(x)
def np_copy_exp(x):
copy = np.ravel(x, 'K')
return np.exp(copy).reshape(x.shape)
তুলনার ন্যায্যতার জন্য, আমি ভিএমএলের সমান্তরালতা বন্ধ করেছি (পরিশিষ্টের কোডটি দেখুন):
যেমনটি দেখতে পাচ্ছে, ভিএমএল একবার লাথি মারল, অনুলিপি করার ওভারহেড ক্ষতিপূরণের চেয়ে বেশি। তবুও একবার এল 3 ক্যাশের জন্য ডেটা খুব বড় হয়ে গেলে সুবিধাটি ন্যূনতম হওয়ায় কাজটি আবার মেমরি-ব্যান্ডউইথ-সীমাবদ্ধ হয়ে যায়।
অন্যদিকে, নাম্বা ইন্টেলের এসভিএমএলও ব্যবহার করতে পারে, যেমনটি এই পোস্টে ব্যাখ্যা করা হয়েছে :
from llvmlite import binding
# set before import
binding.set_option('SVML', '-vector-library=SVML')
import numba as nb
@nb.vectorize(target="cpu")
def nb_vexp_svml(x):
return np.exp(x)
এবং ভিএমএল ব্যবহার করে সমান্তরাল ফলন:
নাম্বার সংস্করণটির ওভারহেড কম রয়েছে, তবে কিছু মাপের জন্য ভিএমএল অতিরিক্ত অনুলিপি ওভারহেড থাকা সত্ত্বেও এসভিএমএলকে বীট করে num যা নাম্বার ইউফুনসগুলি সমান্তরাল না হওয়ায় কিছুটা অবাক হয় না।
তালিকা:
উ: বহুপদী ফাংশনের তুলনা:
import perfplot
perfplot.show(
setup=lambda n: np.random.rand(n,n)[::2,::2],
n_range=[2**k for k in range(0,12)],
kernels=[
f,
vf,
nb_vf
],
logx=True,
logy=True,
xlabel='len(x)'
)
বি এর তুলনা exp
:
import perfplot
import numexpr as ne # using ne is the easiest way to set vml_num_threads
ne.set_vml_num_threads(1)
perfplot.show(
setup=lambda n: np.random.rand(n,n)[::2,::2],
n_range=[2**k for k in range(0,12)],
kernels=[
nb_vexp,
np.exp,
np_copy_exp,
],
logx=True,
logy=True,
xlabel='len(x)',
)