زنجیره

ساخت وبلاگ

Chainrules انواع مختلفی از ابزارهای مشترک را فراهم می کند که می تواند توسط ابزارهای تمایز اتوماتیک پایین دست (AD) برای تعریف و اجرای بدوی های حالت رو به جلو ، معکوس و مختلط مورد استفاده قرار گیرد.

معرفی

Chainrules همه چیز در مورد ارائه مجموعه ای غنی از قوانین برای تمایز است. وقتی شخصی حساب مقدماتی را یاد می گیرد ، می آموزد که مشتق (با توجه به x) A*x A است ، و مشتق گناه (x) cos (x) و غیره است و آنها یاد می گیرند که چگونه قوانین ساده را ترکیب کنند ،از طریق قانون زنجیره ای ، برای تمایز عملکردهای پیچیده. Chainrules یک مخزن برنامه ای از آن دانش است ، با تعمیم در ابعاد بالاتر.

ابزارهای AutoDiff (AD) تقریباً با کاهش یک مشکل به قسمت های ساده ای که آنها قوانین را می شناسند ، و سپس ترکیب آن قوانین کار می کنند. دانستن قوانین برای توابع پیچیده تر ، روند AutoDiff را سرعت می بخشد زیرا لازم نیست همه چیز را تجزیه کند.

Chainrules مجموعه ای از قوانین مستقل از AD است که در یک سیستم تمایز استفاده می شود.

کل این زمینه آشفتگی برای اصطلاحات است

این فقط زنجیره ای نیست بلکه همه هستند. زنجیره های داخلی سعی می کنند سازگار باشند. کمک به آن همیشه مورد استقبال قرار می گیرد.

ابتدایی

اغلب ما در مورد چیزی به عنوان Primal صحبت خواهیم کرد. این بدان معناست که مربوط به مشکل اصلی است ، نه مشتق آن. به عنوان مثال در y = foo (x) ، foo عملکرد اولیه است و محاسبه FOO (x) در حال انجام محاسبات اولیه است. y بازگشت اولیه است و X یک استدلال اولیه است. Typeof (y) و Typeof (x) هر دو نوع اولیه هستند.

Frule و Rrule

`frule` و` rrule`

Frule و Rrule اصطلاحات خاص زنجیره ای هستند. عملکرد دقیق آنها نسبتاً زنجیره ای خاص است ، اگرچه ابزارهای دیگر عملکردهای مشابهی دارند. مفهوم اصلی گاهی اوقات به نام های تبلیغاتی سفارشی ، مجالس سفارشی ، شیب های سفارشی ، حساسیت های سفارشی خوانده می شود.

این قوانین به ترتیب برای استفاده در حالت رو به جلو و تمایز حالت معکوس به عنوان Frule S و Rrule رمزگذاری می شوند.

rrule برای برخی از عملکردهای FOO ، که استدلال های موقعیتی و استدلال های کلمات کلیدی را در نظر می گیرد ، نوشته شده است:

تابع rrule (:: typeof (foo) ، args. ؛ kwargs.). بازگشت y ، پایان بازگرداندن

جایی که y (نتیجه اولیه) باید برابر با FOO باشد (استدلال ها. ؛ kwargs.). بازپرداخت تابعی برای انتشار اطلاعات مشتق به عقب در آن نقطه است. این عملکرد بازپرداخت مانند: - خود ، ∂args استفاده می شود.= عقب نشینی (Δy)

تقریباً همیشه بازپرداخت به صورت محلی در داخل Rrule اعلام می شود و در مورد برخی از استدلال های دیگر بسته می شود و به طور بالقوه در نتیجه اولیه نیز خواهد بود.

frule نوشته شده است:

Function Frule ((ΔSelf ، Δargs.) ، :: Typeof (foo) ، Args. ؛ kwargs.). بازگشت y ، ∂y پایان

جایی که دوباره y = foo (args ؛ kwargs.) ، و ∂y نتیجه انتشار اطلاعات مشتق به جلو در آن نقطه است. این انتشار به صورت pushforward فراخوانی می شود. غالباً ما از این فرج به عنوان محاسبات اولیه y = foo (args. ؛ kwargs.) ، و pushforward ∂y = pushforward (Δelf ، Δargs.) فکر خواهیم کرد ، حتی اگر آنها در اشکال جداگانه در کد وجود ندارند.

چرا `rrule یک بازپرداخت را برمی گرداند اما` frule "یک فشار به جلو را بر نمی گرداند

در حالی که Rrule فقط آرگومان ها را به عملکرد اصلی (آرگومان های اولیه) می برد و یک تابع (بازپرداخت) را که با اطلاعات مشتق کار می کند ، برمی گرداند ، Frule این کار را یکباره انجام می دهد. این امر به این دلیل است که فرل محاسبه اولیه و فشار را به هم می ریزد. این یک بهینه سازی است که به Frule S اجازه می دهد تا شامل عملیات بزرگ و بزرگ باشد که هم محاسبه اولیه را انجام می دهد و هم در همان زمان (برای مثال حل ODE).

این عمل فقط در حالت رو به جلو (جایی که از آن استفاده می شود) امکان پذیر است زیرا اطلاعات مشتق مورد نیاز توسط Pushforward موجود با Frule فراخوانی می شود - این مربوط به ورودی های عملکرد اولیه است. در مقابل ، در حالت معکوس ، اطلاعات مشتق مورد نیاز توسط بازپرداخت در مورد خروجی عملکرد Primal است. بنابراین حالت معکوس عملکرد بازپرداخت را باز می گرداند که تماس گیرنده (معمولاً یک سیستم AD) تا زمانی که اطلاعات مشتق در مورد خروجی در دسترس باشد ، از آن استفاده می کند.

مبلغین: Pushforward و Backback

فشار و بازپرداخت

Pushforward و Pullback کلمات فانتزی هستند که جامعه Autodiff اخیراً از هندسه دیفرانسیل اتخاذ کرده است. به طور گسترده ای با استفاده از بازپرداخت و فشار در هندسه دیفرانسیل مطابقت دارند. اما هر نوع سنجی به شما می گوید این موارد مسطح فوق العاده خسته کننده است. برخی نیز به شما اخم می کنند. آنها همچنین گاهی اوقات از نظر ژاکوبیان شرح داده می شوند: Pushforward محصول بردار Jacobian (JVP) است ، و بازپرداخت محصول بردار Jacobian Transpose (J'VP) است. اصطلاحات دیگری که ممکن است مورد استفاده قرار گیرد شامل بازگرداندن Backpropagator و به قیاس برای فشار برای ForwardPropagator است ، بنابراین این نسخه ها هستند. اینها همچنین نامهای خوبی هستند زیرا به طور مؤثر از طریق قاعده زنجیره ای ، wiggles و wobbles را از طریق آنها پخش می کنند..

ایده اصلی

کمتر رسمی

  • Pushforward با عبور از آن از طریق عملکرد ، یک فضای ورودی را در فضای ورودی می گیرد و به شما می گوید که چه چیزی را در فضای خروجی ایجاد خواهید کرد.
  • بازپرداخت با توجه به خروجی عملکرد ، اطلاعات wobcliness را به خود اختصاص می دهد و با توجه به ورودی توابع ، از لحاظ معادل آن را بیان می کند.

به طور رسمی تر

فشار $ f $ حساسیت ورودی $ f $ را به یک مقدار می رساند و حساسیت خروجی $ f $ را به آن مقدار می دهد که بازپرداخت $ $ حساسیت یک مقدار را به خروجی می دهد$ f $ ، و حساسیت آن مقدار را به ورودی $ f $ می بخشد.

ریاضی

این همه با صحبت در 1D کمی ساده شده است.

ریاضی سبک تر

برای زنجیره ای از عبارات:

a = f (x) b = g (a) c = h (b)

بازگرداندن G ، که دانش ∂B/∂A را شامل می شود ، قانون زنجیره ای را برای رفتن از ∂C/∂B به ∂C/∂A اعمال می کند.

فشار به سمت G ، که همچنین دانش ∂B/∂A را نیز در بر می گیرد ، قانون زنجیره ای را برای رفتن از ∂A/∂x به ∂B/∂x اعمال می کند.

تفسیر هندسی از آگهی حالت معکوس و رو به جلو

بگذارید از نظر هندسی به انواع خود فکر کنیم. به عبارت دیگر ، عناصر یک نوع منیفولد را تشکیل می دهند. این سند با جزئیات بیشتر این دیدگاه را توضیح می دهد.

برخی از اصطلاحات/کنوانسیون ها.

بگذارید $ p $ عنصری از نوع M باشد ، که توسط برخی از تکالیف اعداد $ x_1 تعریف شده است. x_m $ ، بگویید $ (x_1. x_m) = (a_1. 1_m) $

یک تابع $ f: m to k $ در $ m $ (برای سادگی) یک چند جمله ای $ k [x_1 ،. x_m] $

فضای مماس $ t_pm $ t $ در نقطه $ p $ فضای $ $ -Vector $ است که توسط مشتقات $ d/dx $ درج شده است. فضای مماس به صورت خطی در فضای کارکردها عمل می کند. آنها طبق معمول عمل می کنند. نقطه شروع ما این است که ما می دانیم که چگونه $ d/dx (f) = df/dx $ را بنویسیم.

مجموعه فضاهای مماس $ $ برای $ p in m $ بسته نرم افزاری مماس $ m $ نامیده می شود.

بگذارید $ df $ اطلاعات مرتبه اول $ $ را در هر نقطه نشان دهد. به این دیفرانسیل $ f $ گفته می شود. اگر مشتقات $ f $ و $ g $ با $ p $ موافق باشند ، می گوییم $ df $ و $ dg $ همان cotangent را با p $ $ نشان می دهند. کوویکتورهای $ dx_1 ،. dx_m $ اساس فضای cotangent $ t^*_ pm $ را با $ p $ تشکیل می دهد. توجه کنید که این فضای بردار دوتایی به $ t_p $ است

مجموعه فضاهای cotangent $ $ برای $ p in m $ ، بسته نرم افزاری cotangent $ m $ نامیده می شود.

فشار به جلو و عقب

بگذارید $ n $ نوع دیگری باشد ، که توسط شماره $ y_1 تعریف شده است. y_n $ ، و اجازه دهید $ g: m to n $ یک نقشه باشد ، یعنی یک وکتور $ $ $ -بعد (g_1 ،. g_m) $ توابع $ m $.

ما فشار $ g _*را به جلو تعریف می کنیم: tm to tn $ بین بسته های مماس توسط $ g _*(x) (h) = x (g circ h) $ برای هر بردار مماس $ x $ و $ f $. ما $ g _*(d/dx_i) (y_j) = dg_j/dx_i $ داریم ، بنابراین با توجه به مبنای انتخابی ، فشار به جلو با ژاکوبیان مطابقت دارد.

به طور مشابه ، بازگرداندن دیفرانسیل $ df $ توسط $ g^*(df) = d (f circg) $ تعریف شده است. بنابراین برای یک مختصات دیفرانسیل $ dy_j $ ، ما $ g^*(dy_j) = d (g_j) $ داریم. توجه داشته باشید که این یک کوویکتور است ، و ما می توانستیم با عمل آن بر روی بردارها توسط $ g^*(dh) (x) = g _*(x) (dh) = x (g circ h) $ برای هرگونه عقب نشینی تعریف کنیم. عملکرد $ f $ در $ n $ و $ x در TM $. به طور خاص ، $ g^*(dy_j) (d/dx_i) = d (g_j)/dx_i $. اگر این عمل را در پایه ای از فضای cotangent انجام دهید ، می بینید که توسط مجاور ژاکوبیان عمل می کند.

توجه داشته باشید که بازگرداندن یک دیفرانسیل و فشار یک بردار معنای بسیار متفاوتی دارد و این باید در مورد نحوه استفاده از آنها در کد منعکس شود.

اطلاعات موجود در نقشه فشار رو به جلو دقیقاً همان کاری است که عملکرد من با بردارهای مماس انجام می دهد. Backbacks ، با استفاده از دیفرانسیل توابع ، با استفاده از مشتقات کل یک عملکرد عمل می کند. این به روشی متغیر هماهنگ عمل می کند و بدون مفهوم یک متریک کار می کند. فراخوان شیب بردارها هستند ، اما باید اطلاعات مشابهی از دیفرانسیل $ df $ داشته باشند. با فرض اینکه از متریک استاندارد اقلیدسی استفاده می کنیم ، می توانیم $ df $ و $ nabla f $ را به عنوان بردارها شناسایی کنیم. اما کشیدن شیب های عقب هنوز نباید چیزی باشد.

اگر هدف ارزیابی شیب یک تابع $ f = g circ h: m to n to k $ است ، جایی که $ g $ یک نقشه است و $ h $ یک عملکرد است ، ما دو گزینه واضح داریم: اول، ما ممکن است پایه ای از $ m $ تا $ tk $ را که با خود k شناسایی می کنیم ، به جلو سوق دهیم. این منجر به مقیاس $ M $ می شود که نمایانگر اجزای شیب است. گام به گام در مختصات:

  1. محاسبه فشار به جلو پایه $ t_pm $ ، یعنی فقط ستون های Jacobian $ dg_i/dx_j $.
  2. محاسبه فشار به جلو عملکرد $ H $ (آن را به عنوان نقشه در نظر بگیرید ، K نیز یک منیفولد است!) برای دریافت $ H _*(G_*T_PM) = sum_j dh/dy_i (dg_i/dx_j) $ $ $ $

دوم ، ما دیفرانسیل $ dh $ را عقب می کشیم:

  1. محاسبه $ dh = dh/dy_1. DH/DY_N $ در مختصات.
  2. با ضربات (در مختصات) ضرب کنید و با مجلل ژاکوبیان ضرب کنید ، و در نتیجه $ g _*(dh) = sum_i (dg_i/dx_j) (dh/dy_i) $.

آناتومی بازپرداخت و فشار

برای عملکرد ما foo (استدلال. ؛ kwargs.) = y:

بازگرداندن عملکرد (ΔY). خود را برگردانید ، ∂args. پایان

ورودی به بازپرداخت اغلب بذر نامیده می شود. اگر تابع y = f (x) باشد ، بازپرداخت s̄elf نوشته می شود ، x̄ = pullback (ȳ).

توجه داشته باشید

بازپرداخت یک ∂ARG در هر استدلال را به عملکرد اصلی باز می گرداند ، به علاوه خود برای زمینه های خود عملکرد (در زیر توضیح داده شده است).

آشفتگی ، بذر ، حساسیت

گاهی اوقات از آشفتگی ، بذر و حتی حساسیت به صورت متقابل استفاده می شود. آنها به طور کلی مترادف نیستند ، و زنجیره ای نباید آنها را مخلوط کنند. هنگام خواندن ادبیات باید مراقب باشید. در پایان روز ، همه آنها wiggles یا wobbles هستند.

Pushforward بخشی از عملکرد Frule است. به تنهایی در نظر گرفته می شود:

تابع فشار (Δself ، Δargs.). بازگشت

اما از آنجا که به درون فروخته شده است ، ما آن را به عنوان بخشی از:

Function Frule ((ΔSelf ، Δargs.) ، :: Typeof (foo) ، Args. ؛ kwargs.). بازگشت y ، ∂y پایان

ورودی به Pushforward اغلب آشفتگی نامیده می شود. اگر تابع y = f (x) باشد ، غالباً فشار می یابد ẏ = آخرین (frule ((ṡelf ، ẋ) ، f ، x)). ẏ معمولاً برای نشان دادن آشفتگی برای y استفاده می شود.

توجه داشته باشید

در frule /pushforward ، یک ΔARG در هر استدلال به عملکرد اصلی وجود دارد. ΔARG ها در نوع/ساختار با ورودی های مربوطه مشابه هستند (Δself در زیر توضیح داده شده است).∂y در نوع/ساختار با خروجی عملکرد اصلی مشابه است. به طور خاص اگر این تابع یک Tuple را برگرداند ، پس از آن یک قطعه با همان اندازه خواهد بود.

خود مشتق Δself ، خود ، s̄elf ، ṡelf و غیره

Δself ، خود ، s̄elf ، ṡelf

این مشتقات با توجه به زمینه های داخلی عملکرد است. به بهترین دانش ما هیچ اصطلاحاتی استاندارد برای این کار وجود ندارد. نامهای خوب دیگر ممکن است Δinteal / ∂inteal باشد.

از دیدگاه ریاضی ، ممکن است کسی تعجب کند که این همه خود ، خود چیست. با توجه به اینکه عملکردی با دو ورودی ، مثلاً f (a ، b) ، فقط دو مشتقات جزئی دارد: $ dfrac $ ، $ dfrac $. پس چرا یک فشار به جلو در این δ خود اضافی می گیرد ، و چرا یک بازپرداخت این خود را به خود باز می گرداند؟

دلیل این امر این است که در جولیا عملکرد F ممکن است دارای زمینه های داخلی باشد. به عنوان مثال ، بسته هایی دارای زمینه هایی است که از آن بسته می شود. یک شیء قابل تماس (یعنی یک functor) مانند Flux. Dense زمینه های آن شی را دارد.

بنابراین با هر عملکرد به عنوان داشتن استدلال ضمنی اضافی ، که آن زمینه ها را ضبط می کند ، رفتار می شود. بنابراین هر فشار به جلو یک استدلال اضافی می گیرد ، که نادیده گرفته می شود مگر اینکه عملکرد اصلی دارای زمینه باشد. نوشتن تابع foo_pushforward (_ ، Δargs.) در مورد زمانی که FOO دارای زمینه نیست ، معمول است. به طور مشابه ، هر بازپرداخت یک خود را باز می گرداند ، که برای مواردی که بدون زمینه ها وجود دارد ، NO_FIELDS ثابت است ، که نشان می دهد هیچ زمینه ای در خود عملکرد وجود ندارد.

خلاصه Pushforward / Backback

  • عقب کشیدن
    • توسط Rrule بازگشت
    • مبهم های فضای خروجی را می گیرد ، به فضای ورودی می دهد
    • ساختار آرگومان با ساختار خروجی عملکرد اولیه مطابقت دارد
    • اگر عملکرد Primal یک Tuple را برگرداند ، پس از آن ، بازپرداخت در یک قسمت از دیفرانسیل ها قرار می گیرد.
    • 1 بازگرداندن هر آرگومان عملکرد اصلی + 1 برای خود عملکرد
    • قسمتی از فرول
    • wiggles فضای ورودی را می گیرد ، و به فضای خروجی می دهد
    • ساختار آرگومان با ساختار استدلال عملکرد اولیه مطابقت دارد ، اما در شروع Frule به عنوان یک Tuple منتقل می شود
    • 1 آرگومان در هر آرگومان عملکرد اصلی + 1 برای خود عملکرد
    • 1 بازگشت در هر عملکرد اصلی

    بازگرداندن/فشار به سمت بالا و مشتق/گرادیان

    بی اهمیت ترین استفاده از فشار از درون فروپور محاسبه مشتق جهت است:

    اگر می خواهیم مشتق جهت F را برای تغییر ورودی (1. 5 ، 0. 4 ، -1) بدانیم

    جهت = (1. 5 ، 0. 4 ، -1) # (ȧ ، ḃ ، ċ) y ، ẏ = frule ((صفر () ، جهت.) ، f ، a ، b ، c)

    در جهت اصلی ، مشتقات جزئی y می شود:

    y ، ∂y_∂a = frule ((صفر () ، 1 ، 0 ، 0) ، f ، a ، b ، c) y ، ∂y_∂b = frule ((صفر () ، 0 ، 1 ، 0)f ، a ، b ، c) y ، ∂y_∂c = frule ((صفر () ، 0 ، 0 ، 1) ، f ، a ، b ، c)

    به طور مشابه ، بی اهمیت ترین استفاده از Rrule و بازگشت برگشتی برای محاسبه شیب است:

    y ، f_pullback = rrule (f ، a ، b ، c) ∇f = f_pullback (1) # برای دانه مناسب `1 '. s̄elf ، ā ، b̄ ، c̄ = ∇f

    دیفرانسیل

    مقادیری که از عقب نشینی یا فشار به سمت باز می گردند ، همیشه همان نوع ورودی/خروجی عملکرد اولیه نیستند. آنها دیفرانسیل هستند ، که تقریباً مربوط به چیزی است که می تواند تفاوت بین دو مقدار از انواع اولیه را نشان دهد. یک دیفرانسیل ممکن است چنین نوع معمولی ، مانند یک عدد یا یک ماتریس ، مطابق با نوع اصلی باشد. یا ممکن است یکی از زیرگروه های انتزاعی باشد.

    دیفرانسیل تعدادی از عملیات را پشتیبانی می کند. از همه مهمتر: + و * ، که به آنها اجازه می دهد به عنوان اشیاء ریاضی عمل کنند.

    مهمترین انتزاع در هنگام شروع کار ، مواردی است که در مورد اجتناب از کار هستند:

    • Thunk: این یک محاسبه معوق است. Thunk یک کلمه برای بسته شدن استدلال صفر است. محاسباتی پیچیده شده در Thunk تا زمانی که Unthunk در Thunk فراخوانی نشود ، ارزیابی نمی شود. Unthunk یک عدم حضور در ورودی های غیر متقاطع است.
    • یک ، صفر: نمایش های ویژه 1 و 0 وجود دارد. آنها کارهای بسیار خوبی انجام می دهند تا از گسترش Thunks در ضرب و (برای صفر) اضافه کنند.

    سایر موارد انتزاعی S:

    • کامپوزیت: این دیفرانسیل برای توپل ها و ساختارها است. از آن مانند Tuple یا نامگذاری شده استفاده کنید. پارامتر نوع P برای نوع Primal است.
    • Dootexist: صفر مانند ، نشان می دهد که عملیات روی این ورودی متفاوت نیست. نوع اولیه آن به طور معمول عدد صحیح یا بول است.
    • inplaceablethunk: مانند یک thunk است اما می تواند در محل اضافه کند! بشر

    نمونه ای از استفاده مستقیم از زنجیره ای.

    در حالی که Chainrules تا حد زیادی به عنوان یک پس زمینه برای سیستم های Autodiff در نظر گرفته شده است ، می توان از آن به طور مستقیم استفاده کرد. در حقیقت ، اگر بتوانید کد مورد نیاز برای تمایز را محدود کنید ، فقط می تواند بسیار مفید باشد. این زمانی بود که چگونه تمام کد شبکه عصبی کار می کرد.

    استفاده مستقیم از زنجیره ای نیز به شما کمک می کند تا احساس آن را بدست آورید.

    با استفاده از تابع ChainRulescore foo (x) a = sin (x) b = 0. 2 + a c = asin (b) بازگشت C پایان # قوانین تعریف شده (به طور متناوب آنها را از طریق `با استفاده از chainrules") scalar_rule (sin (x) ، coss دریافت کنید.(x)) scalar_rule (+(x ، y) ، (یک () ، یک ())) scalar_rule (asin (x) ، inv (sqrt (1 - x^2)))
    #### DFOO/DX را از طریق rrules #### اولین بار عبور رو به جلو ، جمع آوری قوانین x = 3 ؛a ، a_pullback = rrule (گناه ، x) ؛b ، b_pullback = rrule (+، 0. 2 ، a) ؛c ، c_pullback = rrule (asin ، b) #### سپس شیب محاسبه پاس عقب c̄ = 1 ؛# ∂c/∂c _ ، b̄ = c_pullback (unthunk (c̄)) ؛# ∂c/∂b _ ، _ ، ā = b_pullback (unthunk (b̄)) ؛# ∂c/∂a _ ، x̄ = a_pullback (unthunk (ā)) ؛# ∂c/∂x = ∂f/∂x unthunk (x̄) # خروج ی-1. 0531613736418153
    #### dfoo/dx را از طریق frules x = 3 پیدا کنید. ẋ = 1 ؛# ∂x/∂x nofields = صفر () ؛# ∂self/∂self a ، ȧ = frule ((nofields ، ẋ) ، sin ، x) ؛# ∂a/∂x b ، ḃ = frule ((nofields ، صفر () ، unthunk (ȧ)) ، +، 0. 2 ، a) ؛# ∂b/∂x = ∂b/∂aalla/∂x c ، ċ = frule ((nofields ، unthunk (ḃ)) ، asin ، b) ؛# ∂c/∂x = ∂c/∂b اتوم/∂x = ∂f/∂x unthunk (ċ) # خروج ی-1. 0531613736418153
    #### dfoo/dx را از طریق finitedifferences. jl با استفاده از finitedifferences central_fdm (5 ، 1) (foo ، x)#خروج ی-1. 0531613736418257 ### پیدا کردن dfoo/dx از طریق forwarddiff. jl با استفاده از Forwarddiff Forwarddiff. Deriveative (foo ، x پیدا کنید.) # خروج ی-1. 0531613736418153 #### پیدا کردن dfoo/dx از طریق zygote. jl با استفاده از zygote zygote. gradient (foo ، x) # خروجی (-1. 0531613736418153 ،)
تجارت گزینه های دودویی در ایران...
ما را در سایت تجارت گزینه های دودویی در ایران دنبال می کنید

برچسب : نویسنده : زین‌العابدین مراغه‌ای بازدید : <-PostHit-> تاريخ : جمعه 20 مرداد 1402 ساعت: 13:38