পাইটর্চে "ভিউ" পদ্ধতিটি কীভাবে কাজ করে?


205

আমি view()নিম্নলিখিত কোড স্নিপেট পদ্ধতি সম্পর্কে বিভ্রান্ত ।

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(3, 6, 5)
        self.pool  = nn.MaxPool2d(2,2)
        self.conv2 = nn.Conv2d(6, 16, 5)
        self.fc1   = nn.Linear(16*5*5, 120)
        self.fc2   = nn.Linear(120, 84)
        self.fc3   = nn.Linear(84, 10)

    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(x)))
        x = x.view(-1, 16*5*5)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

net = Net()

আমার বিভ্রান্তি নিম্নলিখিত লাইনটি সম্পর্কে।

x = x.view(-1, 16*5*5)

কী tensor.view()ফাংশন কি? আমি এর ব্যবহার অনেক জায়গায় দেখেছি, তবে কীভাবে এটি এর পরামিতিগুলি ব্যাখ্যা করে তা বুঝতে পারি না।

যদি আমি view()ফাংশনটিকে পরামিতি হিসাবে নেতিবাচক মানগুলি দিয়ে থাকি তবে কী হবে ? উদাহরণস্বরূপ, আমি কল করলে কী হয় tensor_variable.view(1, 1, -1)?

কেউ কি view()উদাহরণের সাথে ফাংশনটির মূল নীতিটি ব্যাখ্যা করতে পারেন ?

উত্তর:


283

দর্শন ফাংশনটি টেনসরকে পুনরায় আকার দেওয়ার জন্য।

বলুন আপনার একটি টেন্সর রয়েছে

import torch
a = torch.range(1, 16)

a1 থেকে 16 পর্যন্ত 16 টি উপাদান রয়েছে (অন্তর্ভুক্ত) এমন একটি টেনসর। আপনি যদি এই টেনসরটিকে পুনরায় আকার তৈরি করতে চান 4 x 4তবে এটি ব্যবহার করতে পারেন

a = a.view(4, 4)

এখন aএকটি 4 x 4টেনসর হবে। নোট করুন যে পুনরায় আকার দেওয়ার পরে মোট সংখ্যক উপাদান একই থাকে। টেন্সর আকৃতিগত aএকটি থেকে 3 x 5টেন্সর উপযুক্ত নাও হতে হবে।

প্যারামিটার -১ এর অর্থ কী?

যদি এমন কোনও পরিস্থিতি থাকে যে আপনি কয়টি সারি চান তা জানেন না তবে কলামগুলির সংখ্যা সম্পর্কে নিশ্চিত, তবে আপনি এটিকে -1 দিয়ে নির্দিষ্ট করতে পারেন। ( দ্রষ্টব্য যে আপনি এটি আরও মাত্রা সহ টেনারগুলিতে প্রসারিত করতে পারেন Only অক্ষের মানগুলির মধ্যে একটি -1 হতে পারে )। লাইব্রেরিটি বলার এটি একটি উপায়: "আমাকে এমন একটি টেনসর দিন যাতে এই বহু কলাম রয়েছে এবং আপনি এটি করতে প্রয়োজনীয় সংখ্যক সারির গণনা করুন"।

এটি আপনি উপরে যে নিউরাল নেটওয়ার্ক কোড দিয়েছেন তা দেখা যাবে। x = self.pool(F.relu(self.conv2(x)))ফরোয়ার্ড ফাংশনে লাইনের পরে , আপনার কাছে 16 টি গভীরতার বৈশিষ্ট্য মানচিত্র রয়েছে। সম্পূর্ণ সংযুক্ত স্তরে এটি দেওয়ার জন্য আপনাকে এটি সমতল করতে হবে। সুতরাং আপনি পাইটরঞ্চকে নির্দিষ্ট সংখ্যক কলামের জন্য আপনি যে টেন্সরটি পেয়েছিলেন তা পুনরায় আকার দিতে এবং এটি নিজেই সারিগুলির সংখ্যা নির্ধারণ করতে বলুন।

নম্পি এবং পাইটরিচের মধ্যে একটি মিল আঁকার viewবিষয়টি নম্পির পুনরায় আকার ফাংশনের অনুরূপ ।


93
"দৃশ্যটি নম্পতির পুনর্নির্মাণের অনুরূপ" - কেন তারা কেবল reshapeপাইটর্চে এটি ডাকেনি ?!
ম্যাক্সবি

54
@ ম্যাক্সবি পুনঃসাপণের পরিবর্তে নতুন টেন্সরটি "ভিউ" দ্বারা ফিরে এসেছে মূল টেনসরের সাথে অন্তর্নিহিত ডেটা ভাগ করে, তাই এটি একেবারে নতুন তৈরি করার পরিবর্তে পুরানো টেনসরটিতে দৃশ্যমান।
কিউকি

37
@ ব্ল্যাকবার্ড "পুনরায় আকারটি সর্বদা স্মৃতি অনুলিপি করে view github.com/torch/cutorch/issues/98
ডিসেম্বর

3
@ ডিভাইনবস্ট টর্চ পুনরায় আকার মেমরির অনুলিপি করে। NumPy পুনরায় আকার না।
তাভিয়ান বার্নস

32

আসুন সহজ থেকে শুরু করে আরও কঠিন কিছু উদাহরণ দিন।

  1. viewপদ্ধতি হিসাবে একই ডেটা সমেত একটি টেন্সর ফেরৎ selfটেন্সর (যার মানে ফিরে টেন্সর উপাদানের একই নম্বর আছে), কিন্তু একটি ভিন্ন আকৃতি সঙ্গে। উদাহরণ স্বরূপ:

    a = torch.arange(1, 17)  # a's shape is (16,)
    
    a.view(4, 4) # output below
      1   2   3   4
      5   6   7   8
      9  10  11  12
     13  14  15  16
    [torch.FloatTensor of size 4x4]
    
    a.view(2, 2, 4) # output below
    (0 ,.,.) = 
    1   2   3   4
    5   6   7   8
    
    (1 ,.,.) = 
     9  10  11  12
    13  14  15  16
    [torch.FloatTensor of size 2x2x4]
  2. ধরে নিচ্ছি যে -1এটি প্যারামিটারগুলির মধ্যে একটি নয়, যখন আপনি তাদের একসাথে গুণাবেন, ফলাফলটি অবশ্যই টেন্সরের উপাদানগুলির সংখ্যার সমান হতে হবে। যদি আপনি না: a.view(3, 3), এটা উঠাবে একটি RuntimeErrorকারণ আকৃতি (3 এক্স 3) 16 উপাদানের সঙ্গে ইনপুট জন্য অবৈধ। অন্য কথায়: 3 এক্স 3 সমান নয় 16 তবে 9।

  3. আপনি -1ফাংশনে পাস হওয়া প্যারামিটারগুলির একটি হিসাবে ব্যবহার করতে পারেন , তবে কেবল একবার। যা ঘটেছিল তা হ'ল পদ্ধতিটি আপনার জন্য সেই অঙ্কটি কীভাবে পূরণ করবে তা গণিত করবে। উদাহরণস্বরূপ a.view(2, -1, 4)সমতুল্য a.view(2, 2, 4)। [16 / (2 x 4) = 2]

  4. লক্ষ্য করুন যে ফিরে আসা টেন্সর একই ডেটা ভাগ করে । যদি আপনি "ভিউ" তে পরিবর্তন করেন আপনি মূল টেনসারের ডেটা পরিবর্তন করছেন:

    b = a.view(4, 4)
    b[0, 2] = 2
    a[2] == 3.0
    False
  5. এখন, আরও জটিল ব্যবহারের ক্ষেত্রে। ডকুমেন্টেশনটিতে বলা হয়েছে যে প্রতিটি নতুন দর্শনের মাত্রা অবশ্যই একটি মূল মাত্রার একটি উপসর্গ হতে হবে, বা কেবল স্পষ্ট ডি, ডি + 1, ..., ডি + কে হবে যা নিম্নলিখিত আইটেমের মতো শর্ত পূরণ করে যে সমস্ত i = 0,। .., কে - 1, স্ট্রাইড [i] = স্ট্রাইড [i + 1] x আকার [i + 1] । অন্যথায়, contiguous()টেন্সরটি দেখার আগে ফোন করা দরকার। উদাহরণ স্বরূপ:

    a = torch.rand(5, 4, 3, 2) # size (5, 4, 3, 2)
    a_t = a.permute(0, 2, 3, 1) # size (5, 3, 2, 4)
    
    # The commented line below will raise a RuntimeError, because one dimension
    # spans across two contiguous subspaces
    # a_t.view(-1, 4)
    
    # instead do:
    a_t.contiguous().view(-1, 4)
    
    # To see why the first one does not work and the second does,
    # compare a.stride() and a_t.stride()
    a.stride() # (24, 6, 2, 1)
    a_t.stride() # (24, 2, 1, 6)

    লক্ষ্য করুন যে a_t, ধীরে ধীরে [0]! = স্ট্রাইড [1] x আকার [1] 24 থেকে ! = 2 x 3


6

torch.Tensor.view()

সরল কথায় বলা যায়, torch.Tensor.view()যা অনুপ্রাণিত হয় numpy.ndarray.reshape()বা numpy.reshape()সেন্সরটির একটি নতুন দৃষ্টিভঙ্গি তৈরি করে, যতক্ষণ না নতুন আকারটি মূল টেনসরের আকারের সাথে সামঞ্জস্যপূর্ণ।

আসুন এটি একটি কংক্রিট উদাহরণ ব্যবহার করে বিস্তারিতভাবে বুঝতে পারি।

In [43]: t = torch.arange(18) 

In [44]: t 
Out[44]: 
tensor([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17])

tআকারের এই টেনসর দিয়ে (18,), কেবলমাত্র নিম্নলিখিত আকারগুলির জন্য নতুন দর্শন তৈরি করা যেতে পারে:

(1, 18)বা equivalently (1, -1)বা বা equivalently বা বা equivalently বা বা equivalently বা বা equivalently বা বা equivalently বা(-1, 18)
(2, 9)(2, -1)(-1, 9)
(3, 6)(3, -1)(-1, 6)
(6, 3)(6, -1)(-1, 3)
(9, 2)(9, -1)(-1, 2)
(18, 1)(18, -1)(-1, 1)

যেহেতু আমরা উপরের আকারের টিউপসগুলি ইতিমধ্যে পর্যবেক্ষণ করতে পারি, শেপ টিপল (যেমন 2*9, 3*6ইত্যাদি) এর উপাদানগুলির গুণনটি সর্বদা মূল টেনসর ( আমাদের উদাহরণস্বরূপ) এর মোট সংখ্যার সমান হতে হবে18

আরেকটি বিষয় লক্ষণীয় যে আমরা -1প্রতিটি আকারের টিপলগুলির একটিতে একটিতে একটি ব্যবহার করেছি । একটি ব্যবহার করে -1, আমরা নিজেই গণনাটি করতে অলসতা বজায় রেখেছি এবং এটি পরিবর্তে নতুন ভিউ তৈরি করার সময় আকৃতির জন্য সেই মানটি গণনা করার জন্য টাইটটিকে পাইটর্চকে অর্পণ করব । একটি গুরুত্বপূর্ণ বিষয় লক্ষণীয় হ'ল আমরা কেবল-1 শেপ টিপলটিতে একটি একক ব্যবহার করতে পারি । অবশিষ্ট মানগুলি স্পষ্টভাবে আমাদের সরবরাহ করা উচিত। অন্য পাইটর্চ একটি নিক্ষেপ করে অভিযোগ করবে RuntimeError:

রানটাইমআরার: কেবলমাত্র একটি মাত্রা অনুমান করা যায়

সুতরাং, উল্লিখিত সমস্ত আকারের সাথে, পাইটর্চ সর্বদা আসল টেনসরের একটি নতুন দৃশ্য ফিরে আসবে t। এটির মূলত অর্থ হল যে এটি অনুরোধ করা প্রতিটি নতুন দর্শনের জন্য সেন্সরটির প্রসারিত তথ্যকে পরিবর্তন করে।

নীচে কয়েকটি নতুন দর্শন দিয়ে টেনারদের ধাপগুলি কীভাবে পরিবর্তন করা হয়েছে তা চিত্রিত করে ।

# stride of our original tensor `t`
In [53]: t.stride() 
Out[53]: (1,)

এখন, আমরা নতুন দর্শনগুলির জন্য পদক্ষেপগুলি দেখতে পাব :

# shape (1, 18)
In [54]: t1 = t.view(1, -1)
# stride tensor `t1` with shape (1, 18)
In [55]: t1.stride() 
Out[55]: (18, 1)

# shape (2, 9)
In [56]: t2 = t.view(2, -1)
# stride of tensor `t2` with shape (2, 9)
In [57]: t2.stride()       
Out[57]: (9, 1)

# shape (3, 6)
In [59]: t3 = t.view(3, -1) 
# stride of tensor `t3` with shape (3, 6)
In [60]: t3.stride() 
Out[60]: (6, 1)

# shape (6, 3)
In [62]: t4 = t.view(6,-1)
# stride of tensor `t4` with shape (6, 3)
In [63]: t4.stride() 
Out[63]: (3, 1)

# shape (9, 2)
In [65]: t5 = t.view(9, -1) 
# stride of tensor `t5` with shape (9, 2)
In [66]: t5.stride()
Out[66]: (2, 1)

# shape (18, 1)
In [68]: t6 = t.view(18, -1)
# stride of tensor `t6` with shape (18, 1)
In [69]: t6.stride()
Out[69]: (1, 1)

সুতরাং যে view()ফাংশন এর যাদু । এটি যতক্ষণ না নতুন দৃশ্যের মূল আকৃতির সাথে সামঞ্জস্যপূর্ণ হয় ততক্ষণ প্রতিটি নতুন দর্শনের জন্য (মূল) সেন্সরটির ধাপগুলি পরিবর্তন করে ।

স্ট্রেডস টিপলস থেকে অন্য একটি আকর্ষণীয় জিনিসটি আপনি পর্যবেক্ষণ করতে পারেন তা হ'ল 0 পজিশনে উপাদানটির মান আকৃতির টিউলের 1 পজিশনে উপাদানটির মানের সমান ।

In [74]: t3.shape 
Out[74]: torch.Size([3, 6])
                        |
In [75]: t3.stride()    |
Out[75]: (6, 1)         |
          |_____________|

এই কারণ:

In [76]: t3 
Out[76]: 
tensor([[ 0,  1,  2,  3,  4,  5],
        [ 6,  7,  8,  9, 10, 11],
        [12, 13, 14, 15, 16, 17]])

অগ্রগতিতে (6, 1)বলা হয়েছে যে 0 তম মাত্রা বরাবর একটি উপাদান থেকে পরবর্তী উপাদানটিতে যেতে , আমাদের লাফিয়ে বা 6 পদক্ষেপ নিতে হবে। (অর্থাত থেকে যেতে 0করার 6, এক 6 পদক্ষেপ নিতে আছে।) কিন্তু এক উপাদান থেকে 1 পরবর্তী উপাদান যেতে St মাত্রা, আমরা শুধু কেবলমাত্র একটি পদক্ষেপ (যেমন থেকে যাওয়া প্রয়োজন 2থেকে 3)।

সুতরাং, গণনা সম্পাদন করার জন্য কীভাবে উপাদানগুলি মেমরি থেকে অ্যাক্সেস করা হয় তার কেন্দ্রবিন্দুতে স্ট্রাইড তথ্য রয়েছে।


torch.reshape ()

এই ফাংশনটি একটি দর্শন ফিরিয়ে দেবে এবং torch.Tensor.view()যতক্ষণ না নতুন আকৃতিটি মূল টেনসরের আকারের সাথে সামঞ্জস্যপূর্ণ তার ব্যবহারের মতোই। অন্যথায়, এটি একটি অনুলিপি ফিরে আসবে।

তবে নোটগুলি torch.reshape()সতর্ক করে যে:

সামঞ্জস্যপূর্ণ পদক্ষেপের সাথে সামঞ্জস্যপূর্ণ ইনপুট এবং ইনপুটগুলি অনুলিপি ছাড়াই পুনরায় আকার দেওয়া যেতে পারে, তবে এক অনুলিপি বনাম দেখার আচরণের উপর নির্ভর করা উচিত নয়।


1

আমি এটির x.view(-1, 16 * 5 * 5)সমতুল্য বুঝতে পেরেছি x.flatten(1), যেখানে প্যারামিটার 1 সমতল প্রক্রিয়াটি 1 ম মাত্রা থেকে শুরু করে ('নমুনা' মাত্রাটি চাটুকা করে না) যেমন আপনি দেখতে পাচ্ছেন, পরেরটির ব্যবহারটি শব্দার্থগতভাবে আরও স্পষ্ট এবং ব্যবহার করা সহজ, তাই আমি পছন্দ করা flatten()


1

প্যারামিটার -১ এর অর্থ কী?

আপনি -1প্যারামিটারগুলির গতিশীল সংখ্যা বা "যে কোনও কিছু" হিসাবে পড়তে পারেন । যে কারণে সেখানে শুধুমাত্র একটি প্যারামিটার হতে পারে -1মধ্যে view()

আপনি যদি এটি জিজ্ঞাসা করেন তবে উপাদানগুলির সংখ্যার উপর নির্ভর করে x.view(-1,1)টেনসর আকারটি আউটপুট দেবে । উদাহরণ স্বরূপ:[anything, 1]x

import torch
x = torch.tensor([1, 2, 3, 4])
print(x,x.shape)
print("...")
print(x.view(-1,1), x.view(-1,1).shape)
print(x.view(1,-1), x.view(1,-1).shape)

আউটপুট দেবে:

tensor([1, 2, 3, 4]) torch.Size([4])
...
tensor([[1],
        [2],
        [3],
        [4]]) torch.Size([4, 1])
tensor([[1, 2, 3, 4]]) torch.Size([1, 4])

1

weights.reshape(a, b) মাপের ওজন হিসাবে একই ডেটা (ক, খ) এর সাথে একটি নতুন টেনসর ফিরে আসবে যেমন এটি মেমরির অন্য অংশে ডেটা অনুলিপি করে।

weights.resize_(a, b)একটি ভিন্ন আকারের সাথে একই টেনসর প্রদান করে। তবে, যদি নতুন আকারটি মূল টেনসারের চেয়ে কম উপাদানগুলিতে ফলাফল দেয় তবে কিছু উপাদান টেনসর থেকে সরানো হবে (তবে স্মৃতি থেকে নয়)। যদি নতুন আকারটি মূল টেনসরের চেয়ে আরও বেশি উপাদানগুলিতে ফলাফল দেয় তবে নতুন উপাদান মেমোরিতে অবিচ্ছিন্ন করা হবে।

weights.view(a, b) আকারের ওজন (ক, খ) এর সমান ডেটা সহ একটি নতুন টেনসর ফিরে আসবে


0

আমি সত্যিই @ জাদিল ডি আরমাসের উদাহরণগুলি পছন্দ করেছি।

আমি। ভিউ (...) এর জন্য কীভাবে উপাদানগুলি অর্ডার করা হচ্ছে তাতে একটি ক্ষুদ্র অন্তর্দৃষ্টি যুক্ত করতে চাই

  • আকার (একটি, খ, সি) সহ একটি টেনসারের জন্য , এর উপাদানগুলির ক্রম একটি সংখ্যা পদ্ধতি দ্বারা নির্ধারিত হয়: যেখানে প্রথম অঙ্কের একটি সংখ্যা থাকে, দ্বিতীয় অঙ্কের বি নম্বর থাকে এবং তৃতীয় অঙ্কের সি সংখ্যা থাকে।
  • নতুন টেন্সর উপাদানের ম্যাপিং .view দ্বারা ফিরে (...) এই অপরিবর্তিত অর্ডার মূল টেন্সর করুন।

0

আসুন নিম্নলিখিত উদাহরণগুলির দ্বারা দৃষ্টিভঙ্গিটি বোঝার চেষ্টা করুন:

    a=torch.range(1,16)

print(a)

    tensor([ 1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9., 10., 11., 12., 13., 14.,
            15., 16.])

print(a.view(-1,2))

    tensor([[ 1.,  2.],
            [ 3.,  4.],
            [ 5.,  6.],
            [ 7.,  8.],
            [ 9., 10.],
            [11., 12.],
            [13., 14.],
            [15., 16.]])

print(a.view(2,-1,4))   #3d tensor

    tensor([[[ 1.,  2.,  3.,  4.],
             [ 5.,  6.,  7.,  8.]],

            [[ 9., 10., 11., 12.],
             [13., 14., 15., 16.]]])
print(a.view(2,-1,2))

    tensor([[[ 1.,  2.],
             [ 3.,  4.],
             [ 5.,  6.],
             [ 7.,  8.]],

            [[ 9., 10.],
             [11., 12.],
             [13., 14.],
             [15., 16.]]])

print(a.view(4,-1,2))

    tensor([[[ 1.,  2.],
             [ 3.,  4.]],

            [[ 5.,  6.],
             [ 7.,  8.]],

            [[ 9., 10.],
             [11., 12.]],

            [[13., 14.],
             [15., 16.]]])

-1 আর্গুমেন্ট ভ্যালু হিসাবে x বলার মান গণনা করার একটি সহজ উপায় যদি আমরা 3 ডি ক্ষেত্রে y, z বা অন্য উপায়ের মান জানি এবং 2d এর জন্য আবার x এর মান গণনা করার সহজ উপায় হ'ল y বা এর বিপরীতে মানগুলি জানুন ..

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.