উপরের উত্তরগুলি কেন খুব ভালভাবে প্রশ্নটিকে সম্বোধন করেছিল । এর ব্যবহারটি আরও ভাল করে বোঝার জন্য আমি একটি উদাহরণ যুক্ত করতে চাই pack_padded_sequence।
একটি উদাহরণ নেওয়া যাক
দ্রষ্টব্য: pack_padded_sequenceব্যাচে (ক্রম দৈর্ঘ্যের অবতরণ ক্রমে) সাজানো ক্রমগুলি দরকার। নীচের উদাহরণে, সিকোয়েন্স ব্যাচটি ইতিমধ্যে কম বিশৃঙ্খলার জন্য বাছাই করা হয়েছিল। পরিদর্শন এই সারকথা লিংক পূর্ণ বাস্তবায়নের।
প্রথমত, আমরা নীচের মতো বিভিন্ন সিকোয়েন্স দৈর্ঘ্যের 2 টি সিকোয়েন্সের একটি ব্যাচ তৈরি করি। ব্যাচে সম্পূর্ণরূপে আমাদের কাছে 7 টি উপাদান রয়েছে।
- প্রতিটি অনুক্রমের আকার 2 এম্বেডিং থাকে।
- প্রথম অনুক্রমের দৈর্ঘ্য রয়েছে: 5
- দ্বিতীয় ক্রমের দৈর্ঘ্য রয়েছে: 2
import torch
seq_batch = [torch.tensor([[1, 1],
[2, 2],
[3, 3],
[4, 4],
[5, 5]]),
torch.tensor([[10, 10],
[20, 20]])]
seq_lens = [5, 2]
আমরা seq_batchসমান দৈর্ঘ্য 5 (ব্যাচের সর্বোচ্চ দৈর্ঘ্য) সহ সিকোয়েন্সগুলির ব্যাচ পেতে প্যাড করি । এখন, নতুন ব্যাচে সম্পূর্ণরূপে 10 টি উপাদান রয়েছে।
padded_seq_batch = torch.nn.utils.rnn.pad_sequence(seq_batch, batch_first=True)
"""
>>>padded_seq_batch
tensor([[[ 1, 1],
[ 2, 2],
[ 3, 3],
[ 4, 4],
[ 5, 5]],
[[10, 10],
[20, 20],
[ 0, 0],
[ 0, 0],
[ 0, 0]]])
"""
তারপরে, আমরা প্যাক padded_seq_batch। এটি দুটি টেনারগুলির একটি দ্বিগুণ ফিরিয়ে দেয়:
- প্রথমটি হচ্ছে সিকোয়েন্স ব্যাচের সমস্ত উপাদান সহ ডেটা।
- দ্বিতীয়টি হ'ল
batch_sizesযা পদক্ষেপগুলি দ্বারা একে অপরের সাথে সম্পর্কিত উপাদানগুলি বলবে।
packed_seq_batch = torch.nn.utils.rnn.pack_padded_sequence(padded_seq_batch, lengths=seq_lens, batch_first=True)
"""
>>> packed_seq_batch
PackedSequence(
data=tensor([[ 1, 1],
[10, 10],
[ 2, 2],
[20, 20],
[ 3, 3],
[ 4, 4],
[ 5, 5]]),
batch_sizes=tensor([2, 2, 1, 1, 1]))
"""
এখন, আমরা packed_seq_batchপাইটরঞ্চের পুনরাবৃত্ত মডিউলগুলিতে যেমন টিপলটি পাস করি, যেমন আরএনএন, এলএসটিএম। এটি কেবল 5 + 2=7পুনরাবৃত্ত মডিউলটিতে গণনা প্রয়োজন ।
lstm = nn.LSTM(input_size=2, hidden_size=3, batch_first=True)
output, (hn, cn) = lstm(packed_seq_batch.float())
"""
>>> output # PackedSequence
PackedSequence(data=tensor(
[[-3.6256e-02, 1.5403e-01, 1.6556e-02],
[-6.3486e-05, 4.0227e-03, 1.2513e-01],
[-5.3134e-02, 1.6058e-01, 2.0192e-01],
[-4.3123e-05, 2.3017e-05, 1.4112e-01],
[-5.9372e-02, 1.0934e-01, 4.1991e-01],
[-6.0768e-02, 7.0689e-02, 5.9374e-01],
[-6.0125e-02, 4.6476e-02, 7.1243e-01]], grad_fn=<CatBackward>), batch_sizes=tensor([2, 2, 1, 1, 1]))
>>>hn
tensor([[[-6.0125e-02, 4.6476e-02, 7.1243e-01],
[-4.3123e-05, 2.3017e-05, 1.4112e-01]]], grad_fn=<StackBackward>),
>>>cn
tensor([[[-1.8826e-01, 5.8109e-02, 1.2209e+00],
[-2.2475e-04, 2.3041e-05, 1.4254e-01]]], grad_fn=<StackBackward>)))
"""
আমাদের outputআউটপুটের প্যাডেড ব্যাচে ফিরে যেতে হবে:
padded_output, output_lens = torch.nn.utils.rnn.pad_packed_sequence(output, batch_first=True, total_length=5)
"""
>>> padded_output
tensor([[[-3.6256e-02, 1.5403e-01, 1.6556e-02],
[-5.3134e-02, 1.6058e-01, 2.0192e-01],
[-5.9372e-02, 1.0934e-01, 4.1991e-01],
[-6.0768e-02, 7.0689e-02, 5.9374e-01],
[-6.0125e-02, 4.6476e-02, 7.1243e-01]],
[[-6.3486e-05, 4.0227e-03, 1.2513e-01],
[-4.3123e-05, 2.3017e-05, 1.4112e-01],
[ 0.0000e+00, 0.0000e+00, 0.0000e+00],
[ 0.0000e+00, 0.0000e+00, 0.0000e+00],
[ 0.0000e+00, 0.0000e+00, 0.0000e+00]]],
grad_fn=<TransposeBackward0>)
>>> output_lens
tensor([5, 2])
"""
এই প্রচেষ্টাটির সাথে স্ট্যান্ডার্ড উপায়ে তুলনা করুন
স্ট্যান্ডার্ড উপায়ে, আমাদের কেবলমাত্র মডিউলটি পাস করতে padded_seq_batchহবে lstm। তবে এর জন্য 10 টি গণনা প্রয়োজন। এটি প্যাডিং উপাদানগুলিতে আরও কয়েকটি গণনা জড়িত যা গণনাগতভাবে অক্ষম হবে।
দ্রষ্টব্য যে এটি ভুল প্রতিনিধিত্বের দিকে পরিচালিত করে না , তবে সঠিক উপস্থাপনাগুলি নিষ্কাশন করতে আরও অনেক যুক্তির প্রয়োজন।
- কেবলমাত্র সামনের দিকের এলএসটিএম (বা কোনও পুনরাবৃত্ত মডিউল) এর জন্য, যদি আমরা একটি সিক্যুয়েন্সের জন্য উপস্থাপনা হিসাবে শেষ ধাপের লুকানো ভেক্টরটি বের করতে চাই, আমাদের টি (ম) ধাপ থেকে লুকানো ভেক্টরগুলি বেছে নিতে হবে, যেখানে টি ইনপুট দৈর্ঘ্য হয়। শেষ উপস্থাপনা বাছাই ভুল হবে। নোট করুন যে ব্যাচের বিভিন্ন ইনপুটগুলির জন্য টি আলাদা হবে।
- দ্বি-নির্দেশমূলক এলএসটিএম (বা যে কোনও পুনরাবৃত্ত মডিউল) এর জন্য এটি আরও বেশি জটিল is কারণ একজনকে দুটি আরএনএন মডিউল বজায় রাখতে হবে, একটি যা ইনপুটটির শুরুতে প্যাডিংয়ের সাথে কাজ করে এবং একটি ইনপুটটির শেষে প্যাডিং সহ, এবং উপরে বর্ণিত হিসাবে অবশেষে লুকানো ভেক্টরগুলি নিষ্কাশন করা এবং সংযুক্ত করা।
আসুন পার্থক্যটি দেখুন:
output, (hn, cn) = lstm(padded_seq_batch.float())
"""
>>> output
tensor([[[-3.6256e-02, 1.5403e-01, 1.6556e-02],
[-5.3134e-02, 1.6058e-01, 2.0192e-01],
[-5.9372e-02, 1.0934e-01, 4.1991e-01],
[-6.0768e-02, 7.0689e-02, 5.9374e-01],
[-6.0125e-02, 4.6476e-02, 7.1243e-01]],
[[-6.3486e-05, 4.0227e-03, 1.2513e-01],
[-4.3123e-05, 2.3017e-05, 1.4112e-01],
[-4.1217e-02, 1.0726e-01, -1.2697e-01],
[-7.7770e-02, 1.5477e-01, -2.2911e-01],
[-9.9957e-02, 1.7440e-01, -2.7972e-01]]],
grad_fn= < TransposeBackward0 >)
>>> hn
tensor([[[-0.0601, 0.0465, 0.7124],
[-0.1000, 0.1744, -0.2797]]], grad_fn= < StackBackward >),
>>> cn
tensor([[[-0.1883, 0.0581, 1.2209],
[-0.2531, 0.3600, -0.4141]]], grad_fn= < StackBackward >))
"""
উপরের ফলাফলগুলি দেখায় যে hn, cnদুটি উপায়ে পৃথক এবং দুটি উপায়ে outputপ্যাডিং উপাদানগুলির জন্য পৃথক মান নিয়ে যায়।