در Torch.Sum و Torch.Tensor.Sum – Community Dev

من علاقه مند هستم که بدانم ، چگونه ، و تا چه اندازه LLMS دارای هوش واقعی هستند ، اما برای فهمیدن این موضوع ، باید بدانم که چگونه آنها کار می کنند. برای این منظور ، من “مقدمه املایی را به مدل سازی زبان: ساختمان Makemore” در لیست پخش YouTube آندره کارپتی “شبکه های عصبی: صفر به قهرمان” تماشا کرده ام. بین زمان های 44:23 و 47:20 ، آندره بینندگان خود را ترغیب می کند تا پاسخ سؤال زیر را از بین ببرند (توجه: من در حال بیان و ساده سازی هستم ، برخی از جزئیات کد آندره را از بین می برد). اجازه دادن tensor
متغیری باشد که دارای یک تانسور Pytorch است – نمونه ای از کلاس torch.Tensor
، نمایندگی
فرض کردن tensor
ابعاد 27×27 دارد. چرا نمی توانیم ارزش بازگشت را فرض کنیم tensor.sum(1)
یکسان با آن است tensor.sum(1, keepdim=True)
، و بنابراین آن tensor / tensor.sum(1)
وت tensor / tensor.sum(1, keepdim=True)
هر دو مورد یک چیز را ارزیابی می کنند؟
از این گذشته ، طبق معناشناسی پخش پیتورچ ، tensor
وت tensor.sum(1, keepdim=True)
قابل پخش هستند ، و tensor
وت tensor.sum(1)
هم همینطور هستند اینقدر tensor
می تواند توسط هر دو تقسیم شود tensor.sum(1, keepdim=True)
یا tensor.sum(1)
بشر و تا زمانی که این دو عملیات تقسیم قانونی باشند ، بلافاصله آشکار نیست که چگونه می توانند نتایج متفاوتی داشته باشند. تانسور تقسیم شده در هر دو حالت یکسان است. و هر یک از تقسیم کننده های متناوب یک تانسور است که حاوی مجموع هر “ردیف” است tensor
در ابعاد 1
بشر متغیر tensor
همچنین در هر دو عملیات بخش دارای همان ارزش است. با توجه به همه این مشترکات ، ارزش چه تفاوتی می تواند باشد keepdim
درست کردن؟
من می دانم که من فقط دانش نسبتاً خوبی را پیش بینی کرده ام. اگر ابتدا ویدیوی آندره را تماشا می کنید ، ممکن است پاراگراف قبلی را بهتر دنبال کنید. ما همچنین آنچه را که من فقط در یک پست آینده گفتم ، باز خواهیم کرد. اما قبل از اینکه حتی سعی کنم به سؤال آندره پاسخ دهم ، من می توانم انجام دهم ، یاد می گیرم که چگونه کد پایتون و مستندات کتابخانه های پایتون مانند Pytorch را بخوانم.
بیایید نگاهی به مستندات برای torch.sum
:
من به پایتون عادت ندارم ، فقط C ++ ، JavaScript و Java. بنابراین وقتی سعی کردم از امضای عملکرد در بالای تصویر استفاده کنم ، روند فکر من تقریباً به شرح زیر پیش رفت.
با tensor
در اختیار ما ، می توانیم از یک عملکرد استفاده کنیم sum
از هر دو روش: torch.sum(tensor, dim)
یا tensor.sum(dim)
بشر هر دو دعوت دقیقاً همان کار را انجام می دهند ، تا آنجا که می توانم بگویم. هر دو sum
در هر دو مورد همان عملکرد است ، یا دو عملکرد با همین نام دارای پیاده سازی های بسیار مشابهی هستند. من با فرضیه قبلی می روم ، زیرا این ساده تر است. بنابراین ، torch
وت tensor
تابعی به نام را به اشتراک بگذارید sum
از طریق اپراتور نقطه قابل دسترسی است ، .
بشر به احتمال زیاد ، پس ، torch.Tensor
و موارد آن ، از جمله tensor
، به ارث بردن sum
از torch
بشر اکنون ، روش ها فقط از انواع و نه از اشیاء جداگانه می توانند به ارث برده شوند. اینقدر torch
باید یک نوع باشد. فراتر از من است که چه نوع نوع است. من شنیده ام torch
به عنوان یک ماژول توصیف شده است. این دلایلی را برای شک و تردید یک کلاس یا رابط کاربری تشکیل می دهد. اما برای همه من می دانم که ماژول ها کلاس ها یا رابط هستند. من با پایتون لنگو مانند “ماژول” چقدر ناآشنا هستم. در همه وقایع به نظر می رسد که sum
یک روش استاتیک از torch
، از آنجا که می توانید آن را صدا کنید torch
خود ، نه فقط نمونه ای از نوع torch
بشر و از آنجا که این روش بدن دارد torch
، من مشکوک هستم torch
رابط کاربری نیست.
باز هم ، این پاراگراف آخر فقط همان چیزی است که من در ابتدا فکر می کردم ، وقتی که من کمی با سواد پایتون بودم. متأسفانه ، استدلال من در آنجا باعث گمراه شدن من شد. torch.sum(input,dim,keepdim=False,*,dtype=None)
امضای یک روش استاتیک نیست. در واقع ، از آن زمان به هیچ وجه امضای روش نیست sum
روشی نیست torch
بشر چرا این روش نیست torch
کمی توضیح می دهد
با تعریف ، یک تابع
است روش از
اگر و فقط اگر (من)
ویژگی متعلق به نوعی است
و (ii)
است یا فوراً است
همانطور که اتفاق می افتد ، عملکرد sum
یک ویژگی از یک نوع است ، یعنی torch.Tensor
بشر بنابراین ، با تعریف ما ، sum
روشی است torch.Tensor
و از هر نمونه آن اما این روشی نیست torch
بشر برای sum
برای اینکه روشی باشد torch
با torch
باید نوعی از آن باشد یا فوری کند sum
یک ویژگی است یک ماژول بودن – که دقیقاً شبیه به بسته جاوا ، یک فضای نام است –torch
یک نوع نیست (یک کلاس/ساختار یا رابط). بنابراین تنها راه sum
می تواند روشی باشد torch
اگر باشد torch
نوعی از آن را فوری می کند sum
یک ویژگی است حالا ، torch
آیا انواع فوری ، یعنی کلاسهای فوق العاده module
کلاس: object
وت module
خود اما sum
ویژگی ای از آن نیست module
یا object
بشر
بنابراین ، در حالی که sum
یک ویژگی از torch
و روشی از torch.Tensor
و نمونه های آن ، این یک روش نیست torch
، چه رسد به یک روش استاتیک torch
بشر
ماژول هایی مانند torch
، به نظر می رسد ، اشیاء موجود در پایتون هستند ، زیرا آنها نمونه هایی از آن هستند module
کلاس. تقریباً همه چیز در پایتون یک شیء است ، از جمله کلاس ها و نمونه هایی مانند int
وت bool
که ممکن است انتظار داشته باشید که ابتدایی باشد ، مانند انواع مربوطه در زبان های دیگر. این توضیح می دهد که چگونه torch
با وجود اینکه یک ماژول به جای یک کلاس یا رابط است ، می تواند ویژگی هایی داشته باشد. . torch
یک رابط است ، نه اینکه به طور آزمایشی حاکم بر این باشد که بر اساس torch
داشتن یک عملکرد قابل تماس.)
پس چگونه انجام می شود torch
وت torch.Tensor
ویژگی را داشته باشید sum
مشترک؟ این نمی تواند باشد Tensor
عملکرد را به ارث می برد sum
از torch
بشر نه می تواند torch
وت Tensor
ارث sum
از نوعی غیر از Tensor
بشر این امر به این دلیل است که فقط انواع ، نه ماژول ها ، می توانند در رابطه وراثت قرار بگیرند.
آنچه اتفاق می افتد این است که Tensor
مشتق کردن sum
از torch
، اما از طریق مکانیسم متفاوتی نسبت به وراثت. تابع sum
در ابتدا در ماژول تعریف شده است torch
، و متعاقباً sum
با کلاس همراه است Tensor
بشر حداقل دو روش وجود دارد که می توان این کار را انجام داد: در داخل و خارج از تعریف Tensor
بشر در اینجا چگونه می توان به تعریف کلاس نگاه کرد:
def sum(input, dim, keepdim=False, *, dtype=None):
# Insert body
class Tensor:
def sum(self, dim, keepdim=False, *, dtype=None):
return sum(self, dim, keepdim, dtype)
# Insert rest of class definition
و خارج از تعریف کلاس:
def sum(input, dim, keepdim=False, *, dtype=None):
# Insert body
class Tensor:
# Insert class definition
Tensor.sum = sum
(توجه: ما تصور می کنیم یکی از قطعه های کد فوق در برخی از پرونده ها موجود است torch
دایرکتوری ماژول/بسته.) به هر صورت ، این میراث واقعی نیست. این در حال استفاده مجدد است torch
اجرای ماژول از sum
اجرای Tensor.sum
، یا از طریق دعوت از torch.sum
در تعریف Tensor.sum
، یا از طریق وصله میمون (اختصاص دادن torch.sum
به Tensor.sum
، بعد از Tensor
تعریف شده است) ما در موعد مقرر خواهیم دید که کدام یک از این دو رویکرد توسعه دهندگان پیوکتورچ باید انجام داده اند ، با فرض اینکه هیچ رویکردی سوم که من از آن غافل شده ام وجود ندارد.
بیایید یک بار دیگر به امضای عملکرد از اسناد نگاه کنیم: torch.sum(input,dim,keepdim=False,*,dtype=None)
بشر چهار پارامتر وجود دارد که وجود دارد input
با dim
با keepdim
وت dtype
، به این ترتیب ویژگی sum
از tensor
باید داشته باشد حداقل این چهار پارامتر نیز از آنجا Tensor.sum
وت torch.sum
در اصل همان عملکرد هستند. اعطا می شود ، یک فرصت خوب وجود دارد tensor.sum
با اولین پارامتر خود به روشی متفاوت از torch.sum
انجام می دهد. برای torch.sum
در سطح ماژول تعریف می شود ، در حالی که tensor.sum
به طور محتمل در سطح کلاس تعریف می شود (همانطور که در بلوک کد اول بالا نشان داده شده است). فرض کنید اینگونه است tensor.sum
تعریف شده است بیشتر فرض کنید که این یک روش غیر استاتیک است. سپس اولین پارامتر آن نمونه کلاس است که در آن عملکرد نامیده می شود. این دقیقاً نحوه کار روشهای غیر استاتیک در پایتون است. بنابراین اولین پارامتر از سمت چپ اپراتور DOT آمده است ، نه آغاز لیست استدلال های محصور در پرانتز. با این وجود ، اولین پارامتر برای دریافت تانسور در نظر گرفته شده است ، همانطور که اولین پارامتر از torch.sum
بشر علاوه بر این ، من فکر می کنم با اطمینان می توانیم فرض کنیم پارامترهای باقیمانده از سه پارامتر آخر قابل تشخیص نیستند torch.sum
بشر
اکنون ، کدام پارامترها کدام آرگومان را در عملکرد تماس می گیرند tensor.sum(1)
وت tensor.sum(1, keepdim=True)
؟ به یاد بیاورید که ما دو سناریو متقابل منحصر به فرد را در حال شمارش هستیم: (الف) که در نتیجه وصله میمون ، tensor.sum
وت torch.sum
پارامترهای یکسانی دارند ، و (ب) که به دلیل tensor.sum
در یک کلاس تعریف شده است ، tensor.sum
وت torch.sum
با توجه به منبع پارامتر اول متفاوت است. ما می توانیم با توجه به اینکه اولین استدلال محصور در پرانتز است ، رد کنیم (الف) 1
در هر دو tensor.sum(1)
وت tensor.sum(1, keepdim=True)
بشر بنابراین (الف) و این واقعیت که 1
به عنوان یک استدلال موقعیتی منتقل می شود ، 1
اولین استدلال ، دوره است. به جای اینکه برای dim
، برای آن گذشت input
بشر اما مانند input
و برخلاف keepdim
وت dtype
با dim
فاقد یک مقدار پیش فرض است. اینقدر dim
به هیچ وجه مقداری اختصاص نمی یابد. مطمئناً اگر اینگونه بود ، tensor.sum(1)
وت tensor.sum(1, keepdim=True)
حداقل یک TypeError
بشر اولین خطایی که پایتون به احتمال زیاد مطرح می کند چیزی شبیه به:
TypeError: sum(): argument 'input' (position 1) must be Tensor, not int
اما در صورت عدم موفقیت ، پایتون بدون شک این خطا را مطرح می کند:
TypeError: sum() missing 1 required positional argument: "input"
از آنجا که هیچ یک از این دو خطا در واقع مطرح نشده است ، ما نشان داده ایم که (الف) اینگونه نیست. مگر اینکه من از سناریوی سوم ، (ج) غافل شده باشم ، این تنها یک امکان در رابطه با پارامترهای پارامترها را به وجود می آورد tensor.sum
و مواردی از torch.sum
: (ب). یعنی اولین استدلال tensor.sum
، کدام عملکرد در یک کلاس تعریف شده است ، باید هر آنچه در سمت چپ اپراتور DOT باشد باشد (برخلاف اولین استدلال torch.sum
، که اولین مورد در لیست محصور در پرانتز در تماس عملکرد است). در دعوت نامه ها tensor.sum(1)
وت tensor.sum(1, keepdim=True)
، یعنی tensor
بشر
من ممکن است از خودم جلو بروم. یک عارضه وجود دارد که من هنوز در مورد آن بحث نکرده ام ، که ممکن است استنباط ما را مسدود کند (ب). این عارضه است ، torch.sum
بیش از حد بارگذاری شده است ، بنابراین دارای یک لیست پارامتر جایگزین است:
فقط یکی از پارامترهای این اضافه بار ، یعنی input
، فاقد یک مقدار پیش فرض است.
بیایید تصریح کنیم که ، به ازای هر پیشنهاد (الف) Tensor
میمون مورد استفاده قرار گرفته است تا یک ویژگی یکسان با آن داشته باشد torch.sum
بشر به این نتیجه می رسد که tensor.sum
بیش از حد اضافه شده است torch.sum
دارد بنابراین حتی اگر فقط یک استدلال بین پارنز تصویب شود ، تا زمانی که این استدلال از نوع صحیح باشد ، هیچ خطایی نخواهد بود. اما در آنجا مالش نهفته است. اولین استدلال اضافه بار torch.sum(input, *, dtype=None)
انتظار می رود یک تانسور است. اینقدر tensor.sum(1)
هنوز یکی از خطاهای ذکر شده در گذشته را افزایش می دهد:
TypeError: sum(): argument 'input' (position 1) must be Tensor, not int
اما ، برخلاف پیش بینی عجول قبلی من ، خطای استدلال از دست رفته مطرح نمی شود. علاوه بر این ، پایتون تفسیر می کند tensor.sum(1, keepdim=True)
به عنوان یک دعوت از اضافه بار با لیست پارامتر بزرگتر ، زیرا فقط این اضافه بار پارامتر نام دارد keepdim
بشر بنابراین ، چه زمانی tensor.sum(1, keepdim=True)
اعدام شده است ، ما باید انتظار داشته باشیم که پایتون هر دو خطایی را که قبلاً پیش بینی کرده ام مطرح کند.
باز هم ، این همه بر این فرض است که (الف) درست است. از آنجا که این پیام های خطا در واقع مطرح نشده اند ، ممکن است استنباط کنیم که (الف) نادرست است. بنابراین ، نتیجه گیری اصلی ما است: (ب) درست است. به این نتیجه می رسد که tensor
برای input
در tensor.sum(1)
وت tensor.sum(1, keepdim=True)
بشر فقط یک تجدید نظر اضافی وجود دارد که می تواند به تصور ما از اجرای آن بپردازد Tensor.sum
بشر پس از tensor.sum()
وت torch.sum(tensor)
همان مقدار را برگردانید ، tensor.sum
باید بیش از حد بارگیری شود torch.sum
معنی دارد torch.sum
وت Tensor.sum
هر کدام دو تعریف داشته باشید:
def sum(input, dim, keepdim=False, *, dtype=None):
# Insert body
def sum(input, *, dtype=None):
# Insert body
class Tensor:
def sum(self, dim, keepdim=False, *, dtype=None):
return sum(self, dim, keepdim, dtype)
def sum(self, *, dtype=None):
return sum(self, dtype)
# Insert rest of class definition
در این مرحله ما می توانیم به طور مستقیم مقادیر را مشخص کنیم dim
با keepdim
وت dtype
دریافت اگر آرگومان های موقعیتی/غیر کلید واژه را در دعوت بگذریم tensor.sum(1)
به torch.sum
به عنوان استدلال کلمات کلیدی ، ما دریافت می کنیم torch.sum(input=tensor, dim=1, keepdim=False, dtype=None)
بشر این دو دعوت معادل هستند. همچنین معادل (به یکدیگر) دعوت نامه ها هستند tensor.sum(1, keepdim=True)
وت torch.sum(input=tensor, dim=1, keepdim=True, dtype=None)
بشر بنابراین ، با توجه به چگونه Tensor.sum
از نظر تعریف شده است torch.sum
با tensor.sum(1)
وت tensor.sum(dim=1, keepdim=False, dtype=None)
معادل هستند ، و همینطور هستند tensor.sum(1, keepdim=True)
وت tensor.sum(dim=1, keepdim=True, dtype=None)
بشر
در پست بعدی من در این سری ، قول می دهم آنچه را که در وهله اول انجام داده ام انجام دهم: به سوال آندره کارپتی پاسخ دهید.