خانه توسعهدهنده تکنولوژی بکاند پایتون ترفندهای Numpy
ترفندهای Numpy
Numpy Array بسیاری از عملیاتها را بازنویسی میکند، بنابراین رمزگشایی از آنها میتواند دشوار باشد. در ادامه مجموعهای از لحظات چالشبرانگیز Numpy و ترفندهای آنها آورده شده است.
فهرست مطالب
Toggleترفند 1: Collection1 == Collection2
در Numpy هنگامی که ==
به دو مجموعه اعمال میشود به معنی مقایسه عنصری است و حاصل آن یک آرایه است. این ترفند را میتوان با سایر عملیاتهایی که ورودی آرایه دارند، ترکیب کرد.
>> X_train, y_train, X_test, y_test = load_CIFAR10(cifar10_dir)
# Training labels (y_train) shape: (50000,)
# to pick out correct y examples for one class (assuming that class is indexed at 5)
>> print(y_train == 5)
# array([False, False, False, ..., False, False, False], dtype=bool)
>> idxs = np.flatnonzero(y_train == 5)
()np.flatnonzero
یک آرایه را بهعنوان ورودی میگیرد. آرایه Boolean در پایتون دارای ویژگی نگاشت True
به 1 و False
به 0 است. بنابراین ()flatnonzero
بهراحتی میتواند ایندکس مواردی که از کلاس 5 هستند را انتخاب کند.
ترفند 2: بردارسازی/حذف حلقه با ()np.tile
گاهی اوقات وقتی میخواهید دو ماتریس را به هم اضافه کنید و مجبورید آنها را بهصورت دستی مرتب و broadcast کنید، میتوانید از ()np.tile
استفاده کنید. ()np.tile
ماتریس فعلی را کپی کرده و به شکلی که میخواهید broadcast میکند. کمترین بعد را 1 نگه دارید تا ماتریس/بردار شما ثابت بماند.
هر حلقه for را میتوان در ()
نوشت و از مزیت عملیات برداری استفاده کرد:
# for a matrix shape of (10,5), assume this is our training example
>> train = np.random.randn(10,5)
# for another matrix shape of (5,5), assume this is our training example
# 5 examples, each example has 5 data points
>> test = np.random.randn(5,5)
# We want to form a matrix of (5, 10), each data point on every row is the
# difference between sum of test-data[j] and train-data[i].
>> train = np.sum(train, axis=1)
>> test = np.sum(test, axis=1)
# duplicate train data of shape (10,) 5 times
>> expanded_train = np.tile(train, [test.shape[0],1])
# (5,10)
>> expanded_test = np.tile(test, [train.shape[0],1])
# (10, 5)
>> expanded_test = expanded_test.T
# (5,10) -> transpose it so we can do subtraction
>> result = expanded_train - expanded_test
# (5,10)
()np.tile
همچنین میتواند برای گسترش آرایهها و امکان ضرب، تقسیم و جمع عناصر مورد استفاده قرار گیرد. با این حال بهتر است برای چنین عملکردی از ()np.expand_dims
استفاده شود، زیرا ()expand_dims
بطور خودکار تشخیص میدهد که گسترش روی کدام بعد باید انجام شود و مانند np.tile
نیازی به ترانهاده نهایی ندارد.
ترفند 3: استفاده از آرایه برای اسلایسینگ جفتی
اسلایسینگ آرایه در Numpy اغلب شگفتانگیز است. این شگفتی از بردارسازی max() hinge-loss در SVM ناشی میشود. تابع زیان چندکلاسی SVM برای تفریق امتیاز کلاس صحیح، به امتیاز کلاس اشتباه نیاز دارد. هنگام ضرب داخلی ماتریس وزن و ماتریس آموزش، ماتریسی به شکل (num_train, num_classes) دریافت میکنید. با این حال چگونه میتوانید امتیاز کلاسهای صحیح را بدون افتادن در حلقه، به دست آورید؟ با فرض اینکه برچسبهای y به شکل (,num_train) باشند.
در این شرایط انتخاب pair-wise میتواند مفید باشد:
>> X = np.random.randn(500, 3073)
>> num_train = X.shape[0]
>> y_label = np.random.randint(10, (500,))
>> W = np.random.randn(3073, 500)
>> scores = X.dot(W)
>> correct_scores = scores[range(num_train),y_label]
اگر عملیات آرایه []
در numpy دارای دو آرگومان (که هر دو آرایه هستند) باشد، Numpy این عملیات pair-wise را اجرا میکند، مانند مثال زیر:
>> a = np.asarray([1,2,3])
>> b = np.asarray([1,2,3])
>> correct_scores = scores[a, b]
این برنامه مقدار [1,1]، [2,2] و [3,3] را از ماتریس امتیازات انتخاب میکند. راه دیگر برای استفاده معکوس از آن، انتساب مقدار است. بنابراین اگر بخواهیم امتیاز label صحیح را برای تابع زیان (loss function) حذف کنیم، میتوانیم به صورت زیر عمل کنیم:
>> scores[range(X.shape[0]), y_label] = 0
با این کار تمام امتیازات label صحیح روی 0 تنظیم میشود. بنابراین وقتی آنها را جمع میکنیم، label صحیح بههیچوجه بر هزینه کلی تأثیر نمیگذارد.
مطلب مشابه: تغییرات PHP 8.0
ترفند 4: استفاده هوشمندانه از : برای استخراج شکل مناسب
گاهی اوقات با یک آرایه سهبعدی با شکل (N, T, D) مواجه میشوید، در حالی که تابع شما باید به شکل (N, D) باشد. در چنین شرایطی ()reshape
بیشتر از آنکه مفید باشد ضرر خواهد داشت. بنابراین یک راهحل ساده برای شما باقی میماند:
for t in xrange(T):
x[:, t, :] = # ...
میتوانید از آن برای استخراج یا تخصیص مقادیر استفاده کنید.
ترفند 5: استفاده از Array بهعنوان اندیس Slicing
Numpy همچنین میتواند یک آرایه دیگر را بهعنوان اسلایسینگ در نظر بگیرد. فرض کنید x یک آرایه اندیسی به شکل (N, T) است. هر اندیس از عناصر x در بازه 0 =< idx < V
قرار دارد و ما میخواهیم چنین آرایه اندیسی را به آرایهای با وزن واقعی تبدیل کنیم. با استفاده از یک ماتریس وزنی w با شکل (V, D)، بهسادگی میتوانیم:
N, T, V, D = 2, 4, 5, 3
x = np.asarray([[0, 3, 1, 2], [2, 1, 0, 3]]) # (N, T)
W = np.linspace(0, 1, num=V*D).reshape(V, D) # (V, D)
# this is the only required line
out = W[x] # (N, T, D)
Numpy از مقدار اصلی x بهعنوان اندیس برای استخراج مقادیر از W استفاده میکند.
ترفند 6: Unfunc at
Numpy گروه خاصی از توابع به نام unfunc دارد. numpy.add ،numpy.subtract و… متعلق به این گروه خاص از توابع هستند. Numpy روشهای ازپیشتعریفشدهای برای این توابع مانند at
دارد. این تابع، عملیات (فرض کنید این عملیات add
یا subtract
باشد) را در مکان(های) مشخصی انجام میدهد.
()ununc.at
سه آرگومان را میگیرد. آرگومان اول ماتریسی است که قصد تغییر آن را دارید، آرگومان دوم اندیسهای ماتریسی است که میخواهید تغییر دهید و آرگومان سوم مقداری است که میخواهید تغییر دهید (بسته به اینکه تابع unfunc
چیست).
یک مثال ساده:
>>> a = np.array([1, 2, 3, 4])
>>> np.add.at(a, [0, 1, 2, 2], 1)
>>> print(a)
array([2, 3, 5, 4])
بیایید به یک مثال پیشرفتهتر نگاه کنیم: از این ترفند برای بهروزرسانی ماتریس جاسازی کلمه (word embedding) استفاده کنید!
# dout: Upstream gradients of shape (N, T, D)
# x: from example in Trick 5 (N, T), indices
# V: the length of total vocabulary
# D: weight matrix dimension
# task here is to build a dW to modify
# the original weight matrix
dW = np.zeros((V, D), dtype=dout.dtype)
np.add.at(dW, x, dout)
توجه کنید که Numpy ماتریس x
را به اندیسهای مجزا تبدیل میکند و از آن برای انتساب مقادیر dout به dW استفاده میکند. dout ،np.add.at
را مسطح میکند تا ابعاد آن (N*T, D)
شود. این با ابعاد x
یعنی (N, T) مقایسه میشود تا ببینیم که آیا حاصلضرب ابعاد x و N*T
با هم مطابقت دارند یا خیر. فقط وقتی این اتفاق بیفتد، شما همان مقدار از آرایههای D
را که در x
دستور داده شده است به dW
نسبت میدهید، که برای گرفتن آرایههای D
نیز اتفاق میافتد.