یادگیری ماشین، علم برنامه نویسی برای کامپیوتر است که کامپیوترها از طریق آن بتوانند با انواع مختلف داده سروکار داشته باشند و قادر به یادگیری از طریق این دادهها باشند. در گذشته برنامهنویسان تمامی الگوریتمها و فرمولهای ریاضی و آماری یادگیری ماشین را به صورت دستی مینوشتند. این طرز کدنویسی آن را به فرآیندی زمانبر، خستهکننده و ناکارآمد تبدیل میکند. اما امروزه توسط کتابخانههای مبتنی بر پایتون، فریم ورکها و ماژولهای بسیار قدرتمندی برای یادگیری ماشین ایجاد شده است، که کدنویسی را آسانتر و کارآمدتر از گذشته کرده است. در این مقاله به آموزش TensorFlow میپردازیم. سعی بر آن شده که با بیانی روان مسایل به طور صریح برای دانشجو تعریف شود و با مثالهایی ساده دانشجو قادر به درک نحوهی کار با این فریم ورک و شروع انجام پروژههای خود گردد.
کتابخانههای پایتون در زمینهی هوش مصنوعی عبارتند از:
Numpy
Scipy
Scikit-learn
Theano
TensorFlow
Keras
PyTorch
Pandas
Matplotlib
لزوم یادگیری مفاهیم پایهای بهمنظور درک بهتر نحوهی عملکرد و پیادهسازی الگوریتمهای یادگیری ماشین توسط این کتابخانهها بر کسی پوشیده نیست. با توجه به استقبال متخصصان در حوزهی علم داده و یادگیری ماشین به کتابخانههای پایتون، ما در تیم تولید محتوای سون لرن قصد داریم تا شما را با همهی این کتابخانهها آشنا کنیم.
TensorFlow یکی از کتابخانههای متن باز بسیار محبوب برای محاسبات عددی با کارایی بالاست که توسط تیم Google Brain در شرکت گوکل ساخته شده است و توسط تیمهای تحقیقاتی گوگل در محصولات مختلفی همچون شناسایی گفتار، جیمیل، تصاویر گوگل، جستجو و ... استفاده میشود.TensorFlow از کتابخانههای مشهور یادگیری ماشین در GitHub میباشد. میتوان گفت گوگل تقریبا در همهی برنامههای کاربردیاش از TensorFlow برای اجرای الگوریتمهای یادگیری ماشین استفاده میکند. به عنوان مثال، اگر از تصاویر گوگل یا جستجوی صوتی گوگل استفاده میکنید، به طور غیرمستقیم از مدلهایTensorFlow بهره میبرید، آنها روی خوشههای بزرگ سختافزار گوگل کار میکنند و در کارهای ادراکی قدرتمنداند.
همانطور که از نام این محصول پیداست، TensorFlow فریم ورکی است که دادههای آن بهصورت تنسور تعریف و اجرا میشوند. همین دلیل سبب میشود تا TensorFlow به یک فریم ورک محبوب برای آموزش و اجرای شبکههای عصبی عمیق در برنامههای کاربردی مبتنی بر هوش مصنوعی تبدیل شود و بهصورت گسترده در تحقیقات مرتبط با یادگیری عمیق بهکار گرفته شود. هدف اصلی مقالهی آموزش TensorFlow معرفی مفاهیم تنسورفلو با بیانی ساده به در کنار ارائهی مثالهایی کاربردی برای درک بهتر موضوع است و فرض بر این است که شما تا حدودی با پایتون آشنا هستید.
مولفهی اصلی TensorFlow گراف محاسباتی شامل گرهها و یالهایی است که از این گرهها عبور میکنند و تنسورهایی است که ورودی و خروجی این گرهها هستند. یادگیری این مفاهیم بهمنظور درک بهتر نحوهی کارکرد این کتابخانه ضروری است. در ادامهی مقالهی آموزش TensorFlow به معرفی هر کدام از این مفاهیم میپردازیم.
در ادامهی مقالهی آموزش TensorFlow به تعریف مفهوم تنسور و گراف محاسباتی میپردازیم.
تنسور یک مفهوم هندسی است که در ریاضیات و فیزیک بهمنظور گسترش مفاهیم اسکالر (کمیت نردهای که با عدد نمایش داده میشود)، بردارها و ماتریسها به ابعاد بالا تعریف میشود. آنچه که میبایست در یادگیری ماشین از تنسور بدانیم این است که تنسور در اینجا مفهومی همچون ساختار داده برای تعریف دادهها و نحوهی کار با آنهاست (مشابه نقشی که ساختار دادهی ماتریس در زبان برنامه نویسی متلب دارد.). تنسور این قابلیت را دارد که حجم بالایی از دادههای عددی را ذخیره کند و همین ویژگی این ساختار داده را برای الگوریتمهای یادگیری عمیق مناسب میسازد. برای درک بهتر تنسور را همچون آرایهای از اعداد که در یک جدول چیده شدهاند، در نظر بگیرید (شکل شمارهی 1).
اعداد اسکالر یک تنسور با بُعد صفر، بردار تنسوری با بُعد یک، ماتریسها بُعد دو و ... . برای مثال در تنسور سه بُعدی با آدرس m*n*p میتوان به ماتریس mاُم و سطر n، ستون pاُم مراجعه کرد. برای درک بهتر، بیایید یک تمرین عملی داشته باشیم: (این تمرین توسط کتابخانهی numpy و صرفاً برای توضیح مفهوم تنسور آورده بیان شدهاست.) فرض کنید که میخواهیم میانگین نمرات یک دانشآموز را در یک درس ذخیره کنیم. برای اینکار از یک تنسور صفر بُعدی برای ذخیرهی این مقدار اسکالر استفاده میکنیم. (در کدهای زیر تابع ndim تعداد ابعاد را برمیگرداند):
import numpy as np
tensor_0D = np.array(5)
print("Average grade: \n{}".format(tensor_0D))
print("Tensor dimensions: \n{}".format(tensor_0D.ndim))
Average grade: 5 Tensor dimensions: 0
حال فرض کنید میخواهیم نمرات سه درس یک دانشجو را ذخیره کنیم. از ساختار آرایه ای استفاده میکنیم که یک تنسور یک بُعدی است:
tensor_1D = np.array([4,6,8])
print("Subject grades: \n{}".format(tensor_1D))
print("Tensor dimensions: \n{}".format(tensor_0D.ndim))
Subject grades: [4 6 8] Tensor dimensions: 1
اگر بخواهیم نمرات سه درس یک دانشجو را که در هر درس سه مرتبه امتحان داده ذخیره کنیم، چه ساختار داده ای داریم؟ یک ماتریس یا تنسور سه بُعدی.
# 2D Tensor (matrix)
tensor_2D = np.array([[0, 1, 1], # Subject 1
[2, 3, 3], # Subject 2
[1, 3, 2]]) # Subject 3
print("Exam grades are:\n{}".format(tensor_2D))
print("Subject 1:\n{}".format(tensor_2D[0]))
print("Subject 2:\n{}".format(tensor_2D[1]))
print("Subject 3:\n{}".format(tensor_2D[2]))
print("Tensor dimensions: \n{}".format(tensor_2D.ndim))
Exam grades are: [[0 1 1] [2 3 3] [1 3 2]] Subject 1: [0 1 1] Subject 2: [2 3 3] Subject 3: [1 3 2] Tensor dimensions: 2
و سرانجام حالتی را در نظر بگیرید که نمرات سه امتحان از سه درس یک دانشجو را برای ترم یک و ترم دو بخواهیم داشته باشیم. همانطور که میبینید ابعاد دادهها در حال افزایش است:
tensor_3D = np.array([[[0, 1, 1], # First quarter
[2, 3, 3],
[1, 3, 2]],
[[1, 3, 2], # Second quarter
[2, 4, 2],
[0, 1, 1]]])
print("Exam grades per quarter are:\n{}".format(tensor_3D))
print("First quarter:\n{}".format(tensor_3D[0]))
print("Second quarter:\n{}".format(tensor_3D[1]))
print("Tensor dimensions: \n{}".format(tensor_3D.ndim)
Exam grades per quarter are: [[[0 1 1] [2 3 3] [1 3 2]] [[1 3 2] [2 4 2] [0 1 1]]] First quarter: [[0 1 1] [2 3 3] [1 3 2]] Second quarter: [[1 3 2] [2 4 2] [0 1 1]] Tensor dimensions: 3
اگر دادههای مسألهی قبل را برای سه دانشآموز متفاوت بخواهیم بخواهیم داشته باشیم:
tensor_4D = np.array([[[[0, 1, 1], # Jacob
[2, 3, 3],
[1, 3, 2]],
[[1, 3, 2],
[2, 4, 2],
[0, 1, 1]]],
[[[0, 3, 1], # Christian
[2, 4, 1],
[1, 3, 2]],
[[1, 1, 1],
[2, 3, 4],
[1, 3, 2]]],
[[[2, 2, 4], # Sofia
[2, 1, 3],
[0, 4, 2]],
[[2, 4, 1],
[2, 3, 0],
[1, 3, 3]]]])
print("The grades of each student are:\n{}".format(tensor_4D))
print("Jacob's grades:\n{}".format(tensor_4D[0]))
print("Christian's grades:\n{}".format(tensor_4D[1]))
print("Sofia's grades:\n{}".format(tensor_4D[2]))
print("Tensor dimensions: \n{}".format(tensor_4D.ndim))
The grades of each student are: [[[[0 1 1] [2 3 3] [1 3 2]] [[1 3 2] [2 4 2] [0 1 1]]] [[[0 3 1] [2 4 1] [1 3 2]] [[1 1 1] [2 3 4] [1 3 2]]] [[[2 2 4] [2 1 3] [0 4 2]] [[2 4 1] [2 3 0] [1 3 3]]]] Jacob's grades: [[[0 1 1] [2 3 3] [1 3 2]] [[1 3 2] [2 4 2] [0 1 1]]] Christian's grades: [[[0 3 1] [2 4 1] [1 3 2]] [[1 1 1] [2 3 4] [1 3 2]]] Sofia's grades: [[[2 2 4] [2 1 3] [0 4 2]] [[2 4 1] [2 3 0] [1 3 3]]] Tensor dimensions: 4
همانطور که در کدها دیدید ابعاد دادهها میتواند تا مقادیر دلخواه افزایش یابد. میتوان گفت که در دنیای یادگیری عمیق که از ساختار دادهی تنسور استفاده میشود، معمولاً ابعاد تنسورها به شکل زیر است:
سریهای زمانی: تنسور سه بعدی
عکس: تنسور چهار بعدی
ویدیو: تنسور پنج بعدی
برای درک بهتر، فرض کنید 64 عکس رنگی دارید که هر عکس 224*224 پیکسل است. چون عکس، رنگی است هر پیکسل سه مقدار داده (RGB) دارد و در کل 64*3*224*224 داده داریم و یک تنسور چهار بُعدی.
گراف محاسباتی یک گراف بدون دور است. هر گره در گراف نشاندهندهی یک عملیات مانند جمع، ضرب و ... است و هر عملیات منجر به تشکیل یک تنسور جدید میشود. شکل 2 یک گراف محاسباتی ساده را نشان میدهد.
یک گراف محاسباتی دارای ویژگیهای زیر است:
رئوس برگ ( گرههایی که هیچ فرزندی ندارند، بهعبارتی یال ورودی ندارند) همیشه تنسور هستند. بدین معنی که یک عملیات هرگز نمیتواند در ابتدای نمودار گراف رخ دهد، در نتیجه هر عملیاتی در گراف باید تنسور یا تنسورهایی را به عنوان ورودی بپذیرد و تنسور(هایی) را به عنوان خروجی تولید کند.
گراف محاسباتی میتواند یک عملیات پیچیده را در یک ترتیب سلسله مراتبی نشان دهد. عبارت e=c*d را میتوان با جایگذاری c=a+b و d=b+1 بهفرم زیر نوشت:
(e=(a+b) * (b+1
پیمایش نمودار به ترتیب معکوس منجر به شکلگیری زیرعباراتی است که برای ساخت عبارت نهایی با هم ترکیب شدهاند.
در پیمایش نمودار رو به جلو، هر گره وابسته به نتیجهی گرههای ماقبل خود است. یعنی e وابسته به c و d وابسته به b، c وابسته به a و b است.
عملیات در گرههای هم سطح، مستقل از یکدیگر است. این یکی از ویژگیهای مهم گراف محاسباتی است. وقتی یک گراف به فرم شکل دو میسازیم، طبیعی است که گرهها در همان سطح به عنوان مثال گرههای c و d از یکدیگر مستقل باشند. این به این معنی است که بیش از ارزیابی d ، نیازی به دانستن مقدار گره c باشد. بنابراین میتوان عملیات این گرههای مستقل را بهصورت موازی انجام داد و اجرا کرد.
همانطور که در پاراگراف قبل اشاره شد، قابلیت اجرای موازی در گرههای موجود در یک سطح این امکان را فراهم میآورد تا عملیاتی بدون نیاز به نتایج همدیگر بهصورت همزمان اجرا شوند. الگوریتمهای موجود در کتابخانهی TensorFlow، از این ویژگی بسیار بهره بردهاند.
TensorFlow این امکان را به کاربران خود میدهد تا از ابزار محاسبات موازی برای اجرای سریع عملیات استفاده کنند. گرهها یا عملیات محاسباتی به طور خودکار برای اجرای محاسبات موازی تنظیم میشوند. همهی این کارها بهطور داخلی اتفاق میافتد، بهطور مثال در گراف بالا عملیات c میتواند بر روی CPU انجام شود و عملیات d بر روی GPU. شکل سه دو چشمانداز اجرای توزیعشده را نشان میدهد:
قسمت چپ در تصویر، یک اجرا از سیستم توزیع شدهی منفرد است که در آن تنها یک نشست منفرد (session) (session یا نشست مفهومی در TensorFlow است که در خلال آن به متغیرهای یک گراف محاسباتی فضای حافظه اختصاص داده شده و متغیرها در طول آن نشست، شناخته شدهاند.) یک کارگر (worker) منفرد ایجاد میکند و کارگر مسئول زمانبندی وظایف (Task Scheduling) بر روی دستگاههای مختلف است.
در مورد قسمت سمت راست تصویر چندین کارگر وجود دارد که این کارگرها میتوانند ماشینهای یکسان یا متفاوتی باشند. هر کارگر متناسب با محیط خود کار میکند یعنی، کارگر پروسس 1، روی ماشین مجزایی کار میکند و عملیات را روی تمامی منابع تحت اختیار خود زمانبندی و تقسیم میکند.
زیرگراف در اصل یک گراف محاسباتی است که خود بخشی از یک گراف اصلی است. بهطور مثال در شکل چهار یک زیرگراف محاسباتی میبینید که بخشی از گراف اصلی است. میتوان گفت یک زیرگراف بیانگر یک زیرعبارت است، یعنی c یک زیرعبارت از e است. همچنین مطابق ویژگی آخر بیان شده برای گرافهای محاسباتی، زیر گرافهای موجود در سطح یکسان از یکدیگر مستقلاند و میتوانند به صورت موازی اجرا شوند و این منجر به افزایش بهرهوری و سرعت اجرا خواهدبود.
TensorFlow عملیات خود را در دستگاههای مختلفی که توسط کارگران اداره میشود، توزیع میکند. دادهها میان دستگاهها به فرم تنسور رد و بدل میشوند. به طور مثال در گراف بالا که e=c*d است، c پس از محاسبه به فرم تنسور درآمده و به گره در سطح بالاتر منتقل میشود. البته در حین انتقال دادهها تأخیر رخ میدهد که این تأخیر به اندازهی تنسور وابسته است.
تا اینجا فهمیدیم که ساختار دادهی میان گرههای گراف محاسباتی به صورت تنسور است. تنسورها میان گرهها با تأخیر جابجا میشوند و مقدار این تأخیر میتواند به ابعاد و اندازهی تنسور و همچنین ویژگیهای دستگاههای اجرایی گرهها وابسته باشد. یکی از ایدههای اصلی جهت فشردهسازی کاهش اندازهی تنسور روش Lossy است. فشردهسازی Lossy اندازه و ابعاد داده را کاهش میدهد و به مقدار ابعاد توجه نمیکند. به این معنی که ممکن است درخلال فشردهسازی مقدار آن نادرست و یا غیر دقیق شود. البته در یک عدد اعشار 32 بیتی میدانیم که بیتهای کم ارزش تأثیر چندانی ندارند. پس تغییر و یا حذف آنها باعث تغییر چندانی در نتیجهی نهایی نمیشود؛ اما این حذف باعث کاهش حجم دادهها بهصورت مؤثر میشود.
تا اینجا به تعریف مفاهیم TensorFlow و آن دسته از ویژگیهایی پرداختیم که این کتابخانه را به زبان محبوب برای متخصصان هوش مصنوعی تبدیل کردهاست:
TensorFlow از ساختار دادهی تنسور برای انجام عملیات استفاده میکند.
در TensorFlow، ابتدا عملیاتی که میبایست انجام شود، تعریف (ایجاد گراف محاسباتی) و سپس اجرا میشود. این عمل باعث میشود که فرآیند بهصورت بهینه اجرا شود و زمان محاسبات بهطور قابل ملاحظهای کاهش یابد.
TensorFlow کدها را قادر میسازد تا بهصورت موازی روی یک یا تعداد بیشتری CPU یا GPU اجرا شود.
موارد بیان شده را میتوان به شکل زیر نیز تعریف کرد:
TF.Graph: بیانگر مجموعهای از عملیات انجام یافته تحت عنوان Tf.Operation است. هر گرهای از گراف نشاندهندهی اجرای عملیاتی بر روی TENSORها است.
TF.Operation: مجموعهی عملیات اصلی که برای اجرای الگوریتم تعریف کردهایم.
TF.Tensor: ساختار دادهای که به عنوان ورودی تعریف میشود و یا نتایج در آن ذخیره میشوند.
در ادامهی مقالهی آموزش TensorFlow با محیط TensorFlow بهصورت عملی آشنا خواهیم شد و با بررسی مثالهای بیشتر به یادگیری بهتر این فریم ورک کمک خواهیم کرد.
TENSORFLOW قابلیت پشتیبانی اجرا بر روی چندین CPU و GPU را به طور موازی دارد. همین اجرای غیرمتمرکز بر روی دستگاهها منجر به افزایش سرعت اجرای الگوریتمهای یادگیری مانند یادگیری عمیق خواهد شد و دیگر نیاز نیست زمان طولانی بر روی آن صرف شود. برای کاربران ویندوز، TENSORFLOW دو نسخهی مختلف تدارک دیده است:
TENSORFLOW با قابلیت پشتیبانی از فقط CPU: اگر کامپیوتر شما روی پردازندههای گرافیکی NVIDIA اجرا نمیشود، تنها میتوانید از این گزینه برای نصب استفاده کنید.
TENSORFLOW با قابلیت پشتیبانی از GPU: برای محاسبات سریعتر میتوانید از این نسخهی TENSORFLOW استفاده کنید. این نسخه در صورت نیاز به ظرفیت محاسباتی قوی کاربرد دارد.
فریم ورک TENSORFLOW روی سیستمعاملهای مختلف قابلیتهای متفاوت دارد. بهتر است برای درک بهتر این موضوع و نصب متناسب با سیستم خود به سایت TENSORFLOW مراجعه کرده و نسخهی متناسب با دستگاه خود را نصب و اجرا کنید.
تمام محاسبات در TENSORFLOW روی یک یا چند TENSOR انجام میشود. هر TENSOR یک شی با سه ویژگی است:
برچسب منحصر بفرد (name)
بُعد (shape)
نوع داده (dtype)
چهار نوع TENSOR که میتوان ایجاد کرد که ما سه مورد اول را در مقالهی آموزش TensorFlow شرح دادهایم:
Variable
Constant
Placeholder
Sparsetensor
یک روش برای ساخت یک TENSOR استفاده از ()tf.constant است. نحوهی تعریف و توضیحات را در زیر ببینید:
tf.constant(value, dtype, name = "")
arguments:
"value": Value of n dimension to define the tensor. Optional
"dtype": Define the type of data:
- `tf.string`: String variable
- `tf.float32`: Float variable
- `tf.int16`: Integer variable
"name": Name of the tensor. Optional. By default: `Const_1:0`
برای ساخت یک TENSOR صفر بُعدی (نردهای، اسکالر) به شکل زیر عمل میکنیم. البته لازم به یادآوری است که برای استفاده از کتابخانه ی TENSORFLOW دستور import tensorflow as tf را پیش از نوشتن قطعه کدها در این محیط مینویسیم.:
import tensorflow as tf
## rank 0
# Default name
r1 = tf.constant(1, tf.int16)
print(r1)
Tensor("Const:0", shape=(), dtype=int16)
TENSOR یک بُعدی به شکل زیر تعریف میشود:
## Rank1
r1_vector = tf.constant([1,3,5], tf.int16)
print(r1_vector)
r2_boolean = tf.constant([True, True, False], tf.bool)
print(r2_boolean)
Tensor("Const_3:0", shape=(3,), dtype=int16) Tensor("Const_4:0", shape=(3,), dtype=bool)
در TENSORیک بُعدی shape شامل یک مقدار است. برای TENSOR دو بُعدی بایستی بعد هر سطر از داده را در یک براکت قرار داد و یک براکت باز و بسته، بیش از حالت تک بُعدی به داده افزود. مثال زیر را ببینید:
## Rank 2
r2_matrix = tf.constant([ [1, 2],
[3, 4] ],tf.int16)
print(r2_matrix)
Tensor("Const_5:0", shape=(2, 2), dtype=int16)
خروجی ماتریس شامل دو سطر و دو ستون است که با مقادیر 1، 2، 3، 4 پر شده است.
برای نمایش سه بُعد باید یک سطح دیگر از براکت را افزود. مثال زیر را ببینید:
## Rank 3
r3_matrix = tf.constant([ [[1, 2],
[3, 4],
[5, 6]] ], tf.int16)
print(r3_matrix)
Tensor("Const_6:0", shape=(1, 3, 2), dtype=int16)
این ماتریس سه سطر و دو ستون دارد. میتوان یک TENSOR یک بُعدی (1D) با 10 عنصر ایجاد کردکه با صفر پر شده باشد (تابع ()tf.zeros).
# Create a vector of 0
print(tf.zeros(10))
Tensor("zeros:0", shape=(10,), dtype=float32)
دستور بعدی ماتریسی با ابعاد 10*10 که با 1 پر شده را ایجاد میکند (تابع ()tf.ones).
# Create a vector of 1
print(tf.ones([10, 10]))
Tensor("ones:0", shape=(10, 10), dtype=float32)
ماتریس m_shape را با سه سطر و دو ستون که با اعداد 10 تا 15 پر شده را، به شکل زیر تعریف میکنیم و با دستور shape. ابعاد را استخراج میکنیم:
# Shape of tensor
m_shape = tf.constant([ [10, 11],
[12, 13],
[14, 15] ]
)
m_shape.shape
TensorShape([Dimension(3), Dimension(2)])
حال با دستورات زیر به ترتیب به تعداد سطر، ستون و کل اندازهی ماتریس m_shape، تنسوری که با یک پر شده باشد، ایجاد میکنیم:
# Create a vector of ones with the same number of rows as m_shape
print(tf.ones(m_shape.shape[0]))
# Create a vector of ones with the same number of column as m_shape
print(tf.ones(m_shape.shape[1]))
# Create a vector of ones with the same number of m_shape.shape
print(tf.ones(m_shape.shape))
هر TENSOR تنها میتواند شامل دادههای همنوع باشد. با دستور زیر نوع داده را میتوان برگرداند:
print(m_shape.dtype)
<dtype: 'int32'>
همچنین نوع دادهی TENSORFLOW را با متد ()tf.cast میتوان تغییر داد. در قطعه کد زیر نوع دادهی اعشاری به صحیح تبدیل میشود.
# Change type of data
type_float = tf.constant(3.123456789, tf.float32)
type_int = tf.cast(type_float, dtype=tf.int32)
print(type_float.dtype)
print(type_int.dtype)
<dtype: 'float32'> <dtype: 'int32'>
اگر آرگومان مربوط به نوع داده حین ایجاد TENSOR، تعیین نشود، TENSORFLOW بهطور خودکار نوع آن را تعریف میکند. بهطور مثال اگر دادهی متن داشته باشید، نوع آن را string درنظر میگیرد.
نحوهی تعریف مقادیر ثابت در TENSORFLOW را با ()tf.constant دیدید. در الگوریتمها دادهها معمولاً در مقادیر متغیراند و برای تعریف آنها در TENSORFLOW از کلاس Variable استفاده میکنیم. این کلاس در گراف محاسباتی گره ای را مشخص میکند که مقادیر آن تغییر میکنند. برای ایجاد یک متغیر از متد ()tf.get_variable استفاده میکنیم. در ادامهی مقالهی آموزش TensorFlow نحوهی بکارگیری و تعریف پارامترهای این متد را میبینید.
tf.get_variable(name = "", values, dtype, initializer)
argument:
"name = "" ": Name of the variable
"values": Dimension of the tensor
"dtype": Type of data. Optional
"initializer": How to initialize the tensor. Optional
If initializer is specified, there is no need to include the `values` as the shape of `initializer` is used.
به عنوان مثال، کد زیر متغیر دو بُعدی با دو مقدار تصادفی ایجاد میکند. به طور پیشفرض، TENSORFLOW یک مقدار تصادفی را برمیگرداند. نام متغیر را var گذاشتیم:
# Create a Variable
## Create 2 Randomized values
var = tf.get_variable("var", [1, 2])
print(var.shape)
(1, 2)
در مثال بعدی متغیری با یک سطر و دو ستون ایجاد میکنیم. مقادیر ابتدایی این TENSORصفر است. برای مثال، زمانی که مدلی را آموزش میدهید باید مقادیر را برای محاسبهی وزن ویژگیها مقداردهی اولیه کنید.
var_init_1 = tf.get_variable("var_init_1", [1, 2], dtype=tf.int32, initializer=tf.zeros_initializer)
print(var_init_1.shape)
(1, 2)
میتوانید مقادیر یک TENSOR ثابت را به یک متغیر اختصاص دهید. یک TENSOR با مقادیر ثابت با متد ()tf.constant ایجاد و به عنوان مقداردهی اولیهی TENSOR متغیر از آن استفاده میکنیم. مقادیر اولیهی متغیر 10، 20، 30 و 40 است و TENSOR متغیر یک ماتریس 2*2 است:
# Create a 2x2 matrixtensor_const = tf.constant([[10, 20],
[30, 40]])
# Initialize the first value of the tensor equals to tensor_const
var_init_2 = tf.get_variable("var_init_2", dtype=tf.int32, initializer=tensor_const)
print(var_init_2.shape)
(2, 2)
میدانیم که TENSORFLOW برای انجام محاسبات الگوریتمهای یادگیری ماشین طراحی شده است. ورودی الگوریتمهای یادگیری ماشین بهطور کلی شامل سه نوع است: یکی آن ورودیهایی است که توسط کاربر الگوریتم در میزان مشخصی تعریف میشوند: مثل نرخ یادگیری، تعداد تکرار مراحل و ... . دستهی بعدی متغیرهایی است که الگوریتم یادگیری ماشین آنها را برای بهینهسازی جواب نهایی میتواند تغییر دهد و در TENSORFLOW آنها را با عبارت tf.variable تعیین میکنند. در TENSORFLOW دادههایی که به الگوریتم به عنوان ورودی عملیاتی داده میشوند با tf.placeholder تعریف میشوند. برای درک بهتر موضوع placeholder را مانند عمل رزرو میز در یک رستوران در نظر بگیرید. فرض کنید که میزی را برای پنج نفر رزرو کردهاید (تخصیص فضا)، ولی درخصوص اینکه چه کسانی را همراه خود به رستوران ببرید، موضوعی اختیاری است (متغیری است که شما به ان مقدار اختصاص خواهید داد.). قاعدهی کلی تعریف این نوع به شکل زیر است:
tf.placeholder(dtype,shape=None,name=None )
arguments:
"dtype": Type of data
"shape": dimension of the placeholder. Optional. By default, shape of the data
"name": Name of the placeholder. Optional
data_placeholder_a = tf.placeholder(tf.float32, name = "data_placeholder_a")
print(data_placeholder_a)
Tensor("data_placeholder_a:0", dtype=float32)
هر Session (جلسه یا نشست) عملیات گراف را اجرا خواهد کرد. برای مقداردهی گراف با TENSORهای متغیر، باید یک نشست باز کنید و در داخل آن عملیاتی برای تولید خروجی اجرا کنید. بیایید برای درک بهتر این مفهوم را با تشریح مثال سادهی ضرب دو عدد شروع کنیم.
import tensorflow as tf
# Variables definition
x = tf.constant(6)
y = tf.constant(8)
# Operations definition
result = tf.multiply(x, y)
print(result)
Tensor("Mul=0", shape=(), dtype=int32)
همانطور که میبینید نتیجه عددی برنمیگرداند و فقط شبکهای از TENSOR ایجاد شده است. برای درک بهتر مسأله مثال رانندگی با اتومبیل را در نظر بگیرید. مثل این است که تا اینجای کار فقط قطعات اتومبیل مونتاژ شدهاند و برای رسیدن به هدف طراحی این اتومبیل یعنی حرکت کردن، باید آن را روشن کرد. همین کار در TENSORFLOW معادل استفاده از مفهومی تحت عنوان Session یا نشست یا جلسه است.
sess = tf.Session()
output = sess.run(result)
print(output)
48
پس از اجرای عملیات session ایجاد شده را با دستور ()sess.close خاتمه میدهیم تا منابع اختصاص یافته به این نشست آزاد شوند. همانطور که مشاهده نمودید مراحل شامل ایجاد TENSOR برای ورودی، تعریف عملیات ضرب روی آنها، ایجاد سشن و چاپ خروجی است. همانطور که اشاره کردیم، در TENSORFLOW عملیات در قالب یک گراف محاسباتی انجام میپذیرد. گراف محاسباتی مجموعهای از یک سری عملیات ریاضی است که در یک ترتیب خاصی محاسبه میشوند. برای مثال محاسبهی عبارت e=c*d که در آن c= a+b و d=b-1 به فرم گراف زیر است:
این گراف دو ورودی a و b را میگیرد و خروجی e را میدهد. هر گره در این گراف ورودی(ها)یی را میگیرد و محاسباتی را انجام میدهد و خروجی(ها) را به گره بعدی میدهد. میتوان این گراف محاسباتی را در TENSORFLOW به شکل زیر ایجاد کرد.
a = tf.placeholder(tf.float32)
b = tf.placeholder(tf.float32)
c = tf.add(a, b)
d = tf.sub(b, 1)
e = tf.mul(c, d)
در کد بالا شما placeholder ای تحت عنوان a ایجاد کردهاید و فضایی به اندازهی اعشار 32 بیتی به آن اختصاص دادهاید. حال مقدار این a (که ساختار دادهی TENSOR دارد) برابر مقداری است که شما بهعنوان دادهی ورودی گراف محاسباتی (یا همان دادهی آموزشی یک الگوریتم یادگیری ماشین) به آن اختصاص میدهید و خروجی الگوریتم یادگیری ماشین را براساس آن ارزیابی میکنید. اینکه حین تعریف placeholderها آن را 64 بیتی یا 32 یا 16 بیتی در نظر بگیرید بسته به این دارد که فضای مصرفی و زمان اجرای برنامه اولویت است یا دقت خروجی، که اگر 32 بیت در نظر بگیرید به توازنی میان این دو معیار دست یافتهایم.
with tf.Session() as session:
a_data, b_data = 3.0, 6.0
#feed_dict={data_placeholder_a: data}: Feed the placeholder with data
feed_dict = {a: a_data, b:b_data}
output = session.run([e], feed_dict=feed_dict)
print(output)
پس از ایجاد یک session برای این گراف محاسباتی، مقداری که برای یک placeholder در ورودی گرفته میشود از طریق آرگومان feed_dict به گراف محاسباتی ارسال میشود و پس از اجرا خروجی مورد نظر یعنی 45 چاپ میشود.
ما میتوانیم برای اینکه به TENSORFLOW نشان دهیم که چه دستگاههایی را روی کامپیوتر ما برای اجرا میتواند انتخاب کند از دستور زیر استفاده کنیم تا لیست CPU و GPUهای موجود را داشته باشیم:
from tensorflow.python.client import device_libdef get_available_devices():
local_device_protos = device_lib.list_local_devices()
return [x.name for x in local_device_protos]print(get_available_devices())
['/device:CPU:0', '/device:XLA_CPU:0', '/device:XLA_GPU:0', '/device:GPU:0']
اگر خروجی بالا را داشتیم، به طور مثال GPU0 را انتخاب میکنیم و ضرب [3,3] در [2,2] را که حاصل 3*2+3*2=12 است را به شکل قطعه کد زیر محاسبه میکنیم:
with tf.Session() as sess:
with tf.device("/GPU:0"):
matrix1 = tf.constant([[3., 3.]])
matrix2 = tf.constant([[2.],[2.]])
product = tf.matmul(matrix1, matrix2)
output = sess.run(product)
print(output)
با دستور with tf.Session() as sess میتوان به پایتون این امکان را داد که منابع Session را بهطور خودکار آزاد کند.
دستور زیر یک TENSOR تک بُعدی (1D) با 64 مقدار را مابین 5- و 5+ را ایجاد میکند:
n_values = 64
x = tf.linspace(-5.0, 5.0, n_values)
sess = tf.Session()
result = sess.run(x)
print(result)
علاوه بر دستور ()sess.run میتوان از (x.eval(session=sess برای ارزیابی TENSOR هم استفاده کرد و فراموش نکنیم که در پایان ()sess.close را بنویسیم. همچنین میتوان از یک نشست تعاملی (Interactive Session) به جای ()run. استفاده نمود.
تا این قسمت از مقالهی آموزش TensorFlow مثالهای سادهای جهت آشنایی شما و درک بهتر خط کدهای TENSORFLOW را بررسی کردیم. کدهای ما حالت ایستا داشت و الگوریتم به یادگیری نمیپرداخت. در ادامهی مقالهی آموزش TensorFlow به بررسی یک مثال عملی در رابطه با یادگیری ماشین خواهیم پرداخت.
Tensorflow ابزار بسیار گستردهای را برای کنترل کامل محاسبات فراهم میکند. این کار با API سطح پایین (Low level API) انجام میشود. علاوه بر این Tensorflow به مجموعهی گستردهای از APIهای سطح بالا برای انجام بسیاری از الگوریتمهای یادگیری ماشین مجهز شده است. Tensorflow این APIهای سطح بالا را تحت عنوان تخمینگر (Estimator) فراخوانی میکند.
API سطح پایین: معماری را میسازد و مدل را بهینهسازی میکند. کار با این سطح برای یک مبتدی پیچیده است.
API سطح بالا: الگوریتم را به راحتی تعریف میکند و کار با آن راحت است. Tensorflow جعبه ابزاری (ToolBox) تحت عنوان Estimator را برای ساخت، آموزش، ارزیابی و ایجاد یک مدل برای پیشبینی را در اختیار کاربران خود قرار داده است.
در مقالهی آموزش TensorFlow فقط از تخمینگر برای آموزش مدل پیشبینی توسط رگرسیون خطی (Linear Regression) استفاده خواهد شد. با کمک این ToolBox محاسبات سریعتر و آسانتر اجرا میشوند. بخش اول آموزش چگونگی بهکارگیری بهینهساز گرادیان کاهشی (ِGradient Descent Optimizer) را برای آموزش رگرسیون خطی توصیف میکند. همچنین در قالب یک مثال عملی مجموعه دادهی Boston برای پیشبینی قیمت یک خانه به کمک تخمینگر Tensorflow به کار گرفته خواهد شد.
در ادامهی مقالهی آموزش TensorFlow به آموزش مدل رگرسیون خطی در تنسورفلو میپردازیم.
قبل از آموزش مدل، بیایید با رگرسیون خطی آشنا شویم. تصور کنید که دو متغیر فرضی x و y دارید و کار شما پیشبینی مقدار مجهول y براساس مقدار متغیر x است که مقدار آن مشخص است. اگر دادهها را در نمودار ترسیم کنید میتوانید رابطهی مستقیم بین متغیر مستقل x و متغیر وابستهی y را ببینید که به شکل زیر است.
همانطور که میبینید اگر x=1 باشد y تقریبا برابر 6 است و اگر x=2 باشد y حدودا 8.5 خواهد بود. این یک روش دقیق برای پیشبینی y نیست و مستعد خطاست، بهخصوص با مجموعه دادهای که صدها هزار نقطه میتواند داشته باشد. رگرسیون خطی با یک معادله ارزیابی میشود. متغیر y توسط یک یا تعداد بیشتری از متغیرها میتواند محاسبه شود. در مثال قبلی فقط یک متغیر مستقل وجود دارد(x). اگر بخواهیم معادلهی مربوط به آن را بنویسیم به شکل زیر خواهد بود:
که در آن پارامترها به شرح زیر هستند:
منظور از خطای مدل تفاوت مقدار پیشبینی شده با مقدار واقعی است. تصور کنید که مدل را تنظیم کرده و راهحل زیر را برای آن یافتهاید. (منظور از تنظیم یا fit کردن یعنی مقادیر پارامترها به گونهای محاسبه شوند که معادلهی خط حاصل به ازای x نزدیکترین مقدار به y را تولید کند.)
اگر این اعداد را در معادله جایگزین کنیم تبدیل به فرم زیر میشود:
y=3.8+2.78 x
شما اکنون میتوانید مقادیر بهتری برای y از طریق جایگذاری x در معادلهی بالا بیابید. شکل زیر نمودار حاصل از جایگذاری x را در معادلهی فوق نشان میدهد.
خط قرمز حاصل از به هم پیوستن مقادیر پیشبینی شده برای y بر اساس متغیر x در معادلهی فوق است. بر اساس این خط میتوان مقادیر y را برای xهای بزرگتر از 2 نیز پیشبینی کرد. اگر بخواهید رگرسیون خطی را برای همبستگیهای بیشتر گسترش دهید میتوانید متغیرهای بیشتری را به مدل اضافه کنید. تفاوت میان تحلیلهای سنتی و رگرسیون خطی این است که رگرسیون خطی تعیین میکند که y به مجموعهای از متغیرهای مستقل چگونه همزمان واکنش نشان میدهد. در حالی که در روش تحلیل همبستگی چگونگی وابسته بودن y را به هر متغیر مستقل، به صورت دوبهدو و جداگانه بررسی میکند. بیایید مثالی را بررسی کنیم. فرض کنید میخواهید فروش مغازهی بستنیفروشی را پیشبینی کنید. مجموعه داده شامل اطلاعات مختلفی مثل وضعیت آب و هوا (بارانی، آفتابی و ابری) و اطلاعات مشتریان (همچون حقوق، جنسیت و وضعیت تأهل) است. تحلیل سنتی سعی در پیشبینی فروش از طریق محاسبهی میانگین برای هر متغیر به صورت جداگانه میکند و برای سناریوهای مختلف مقدار فروش را تخمین میزند. این امر منجر به پیشبینیهای ضعیف و غیردقیق میشود و تحلیل را به انتخاب سناریوهای خاص محدود میکند. اما اگر شما از رگرسیون خطی استفاده کنید میتوانید معادلهی زیر را برای فروش بنویسید:
الگوریتم رگرسیون خطی بهترین جواب را برای وزنها (ضرایب متغیرها) و مقدار بایاس پیدا میکند. این به این معنی است که الگوریتم سعی در مینیمم سازی هزینه دارد و برای این کار رابطهی sales را با کلیهی متغیرهای مستقل به صورت یکجا بررسی میکند. (منظور از هزینه تفاوت میان مقدار معادلهی خط یافتهشده و مقدار متغیر وابستهی نقاط مجموعه داده است).
الگوریتم یک عدد تصادفی به ازای هر آلفا و بتا انتخاب میکند و مقدار متغیر x را برای محاسبهی y جایگذاری میکند. اگر مجموعه داده شامل 100 نمونه باشد الگوریتم 100 مقدار برای y پیشبینی میکند. میتوانیم مقدار خطا را محاسبه کنیم که تحت عنوان اپسیلن (€) در مدل آورده شده و برابر تفاوت میان مقدار پیشبینیشده توسط مدل و مقدار واقعی است. مقدار خطای مثبت بدین معنی است که الگوریتم مدل y پیشبینیشده را کمتر از مقدار واقعی و مقدار خطای منفی یعنی اینکه مدل، y را بیش از مقدار واقعی تخمین زده است.
هدف این است که مربع خطا را مینیمم کنیم. الگوریتم میانگین مربع خطا را محاسبه میکند. به این مرحله مینیممسازی خطا میگویند. برای رگرسیون خطی میانگین مربع خطا (MSE(Min Square Error نیز نامیده میشود. که از نظر ریاضی به این صورت است:
هدف یافتن بهترین ماتریس وزنی است که MSE را مینیمم کند. اگر میانگین خطا بزرگ باشد به این معنی است که مدل ضعیف عمل میکند و وزنها به خوبی انتخاب نشدهاند. برای اصلاح وزنها به یک بهینهساز نیاز است. بهینهساز مرسوم گرادیان کاهشی (Gradient Descent) با گرفتن مشتق وزنها را کم و زیاد میکند. اگر مشتق مثبت باشد وزن کاهش مییابد و اگر منفی باشد وزن افزایش مییابد.
مدل، وزنها را بروزرسانی میکند و مقدار خطا را دوباره محاسبه میکند. این فرایند تا زمانی که مقدار خطا تغییر نکند تکرار میشود. هر مرحله یک تکرار (Iteration) نامیده میشود. علاوه بر این گرادیانهادر یک نرخ یادگیری ضرب میشوند که بیانگر سرعت یادگیری است. اگر نرخ یادگیری مقدار خیلی کوچکی باشد باعث میشود که زمان همگرایی الگوریتم طولانیتر شود. (یعنی تعداد تکرار بیشتری نیاز داشته باشد.) اگر نرخ یادگیری مقدار خیلی بزرگی داشته باشد باعث میشود که الگوریتم هرگز همگرا نشود.
همانطور که در شکل بالا میبینید، مدل بیست مرتبه پیش از یافتن یک مقدار پایدار برای وزنها تکرار میشود و سپس به کمترین میزان خطا دست مییابد. توجه کنید خطا به صفر نمیرسد بلکه حدود مقدار 5 پایدار و بدون تغییر میشود. این به این معنی است که مدل خطایی با مقدار 5 دارد. اگر بخواهیم خطا را کاهش دهیم نیاز به افزودن دادههای بیشتری به مدل، مثل متغیرهای بیشتر و یا استفاده از تخمینگرهای متفاوتی داریم.
حال که مفهوم رگرسیون خطی را فهمیدهاید قادر به بهکارگیری API تخمینگر ارائه شده توسط Tensorflow برای آموزش اولین رگرسیون خطی خود هستید. در این آموزش از مجموعه دادهی Boston که شامل متغیرهای زیر است استفاده میکنیم.
این مجموعه داده را به سه قسمت به شرح زیر تقسیم خواهیم کرد:
هدف بهکارگیری ویژگیهای مجموعه داده برای پیشبینی ارزش قیمت یک خانه است. در ادامهی آموزش TensorFlow ، شما یاد خواهید گرفت که چگونه و از طریق دو روش مختلف داده را وارد محیط Tensorflow کنید. توجه کنید که هر دوی این روشها نتایج یکسانی در پی دارند:
دوباره یادآوری میکنیم که در این آموزش، نحوهی چگونگی استفاده از API سطح بالا برای ایجاد و آموزش ارزیابی یک مدل رگرسیون خطی در تنسورفلو را یاد خواهید گرفت. اگر شما از یک API سطح پایین برای این کار استفاده کنید میبایست تابع Loss Function، بهینهسازی، گرادیان کاهشی، ضرب ماتریسی، گراف و تنسور را به صورت دستی تعریف کنید که اینها برای افراد مبتدی پیچیدهاند.
برای آموزش مدل باید کتابخانههای مربوط را نصب و فعالسازی کنید. (در صورت نیاز میتوانید به مقالهی آموزش Pandas مراجعه کنید.)
import pandas as pd
from sklearn import datasets
import tensorflow as tf
import itertools
نام ستونها (ویژگی) را تعریف و در متغیر COLUMNS ذخیره میکنید. میتوانید از تابع ()pd.read_csv برای وارد کردن دادهها استفاده کنید.
COLUMNS = ["crim", "zn", "indus", "nox", "rm", "age",
"dis", "tax", "ptratio", "medv"]
#-------------------------------------------------
training_set = pd.read_csv("E:/boston_train.csv", skipinitialspace=True,skiprows=1, names=COLUMNS)
test_set = pd.read_csv("E:/boston_test.csv", skipinitialspace=True,skiprows=1, names=COLUMNS)
prediction_set = pd.read_csv("E:/boston_predict.csv", skipinitialspace=True,skiprows=1, names=COLUMNS)
میتوان شکل (ابعاد) داده را با دستور زیر به دست آورد:
print(training_set.shape, test_set.shape, prediction_set.shape)
(400, 10) (100, 10) (6, 10)
توجه کنید که برچسب (منظور مقدار y در معادلهی رگرسیون یا همان ارزش قیمت خانه در مسئله) در مجموعه داده Boston وجود دارد. بنابراین باید دو لیست دیگر را تعریف کنید. یکی تنها شامل ویژگیها و دیگری تنها با نام برچسب. این دو لیست به تخمینگر شما ویژگیهای مجموعه داده و نام ستون برچسب هر کلاس را نشان خواهد داد. از طریق کد زیر این کار را انجام میدهیم:
FEATURES = ["crim", "zn", "indus", "nox", "rm",
"age", "dis", "tax", "ptratio"]
LABEL = "medv"
باید متغیرهای عددی را به فرمت مناسب تبدیل کرد. Tensorflow متدی را برای تبدیل متغیرهای پیوسته تحت عنوان ()tf.feature_column.numeric_column در اختیار شما قرار میدهد. در گام قبلی شما لیستی از ویژگیهایی که برای مدل در نظر داشتید را تعریف کردید. اکنون از این لیست برای تبدیل آنها به دادهی عددی میتوانید استفاده کنید. اگر میخواهید ویژگیهایی را در مدل خود حذف کنید این کار را پیش از ساخت ستونهای ویژگی مدل خود (feature_cols) انجام دهید.
feature_cols = [tf.feature_column.numeric_column(k) for k in FEATURES]
در این مرحله شما نیاز به تعریف تخمینگر دارید. Tensorflow در حال حاضر شش تخمینگر از پیشساختهشده را فراهم میکند که سه تای آن برای طبقهبندی (Classification) و سه تای آن برای رگرسیون بهکار میرود.
تخمینگر رگرسیون (Regressor):
تخمینگر طبقهبندی (Classifier):
در این آموزش از Linear Regressor استفاده خواهیم کرد. برای دسترسی به این تابع از tf.estimator استفاده میکنیم. برای تابع tf.estimator باید دو آرگومان تعریف شود:
Model_dir : مسیر ذخیرهسازی گراف، ذخیرهی پارامترهای مدل و ... . Tensorflow به طور اتوماتیک فایلی تحت عنوان train در دایرکتوری کاری شما ایجاد میکند. شما باید این مسیر را برای دستیابی به تنسوربرد (Tensor board) استفاده کنید.
estimator = tf.estimator.LinearRegressor(
feature_columns=feature_cols,
model_dir="train")
INFO:tensorflow:Using default config. INFO:tensorflow:Using config: {'_model_dir': 'train', '_tf_random_seed': None, '_save_summary_steps': 100, '_save_checkpoints_steps': None, '_save_checkpoints_secs': 600, '_session_config': None, '_keep_checkpoint_max': 5, '_keep_checkpoint_every_n_hours': 10000, '_log_step_count_steps': 100, '_train_distribute': None, '_service': None, '_cluster_spec': <tensorflow.python.training.server_lib.ClusterSpec object at 0x1a215dc550>, '_task_type': 'worker', '_task_id': 0, '_global_id_in_cluster': 0, '_master': '', '_evaluation_master': '', '_is_chief': True, '_num_ps_replicas': 0, '_num_worker_replicas': 1}
قسمت پیچیدهی کار با Tensorflow نحوهی فیددهی مدل (وارد کردن دادهها) است. Tensorflow برای کار با محاسبات موازی و مجموعه دادههای بزرگ طراحی شده است. به خاطر محدودیت منابع کامپیوتر فیددهی مدل با همهی دادهها به طور همزمان غیرممکن است. برای این کار شما باید هر بار دستهای از دادهها (Batch of Data) را به مدل بدهید. توجه داشته باشید که ما در مورد مجموعه دادههای عظیم با میلیونها داده یا حتی بیشتر صحبت میکنیم. اگر به صورت دستهای دادهها را اضافه نکنید در نهایت با خطای حافظه مواجه خواهید شد. به طور مثال اگر دادهی شما شامل صد نمونه باشد و شما دستهی دادهای به اندازهی دهتایی تعریف کنید این به این معنی است که مدل ده نمونه به ازای هر تکرار مشاهده خواهد کرد (10*10). وقتی که مدل تمامی دادهها را دریافت کرد یک دوره (Epoch) را تمام میکند هر دوره تعیین میکند که چند مرتبه شما میخواهید مدل، کل داده را مشاهده کند.
موضوع بعدی این است که شما دادهها را قبل از هر تکرار تغییر دهید یا ترکیب کنید. در طول آموزش مدل تغییر دادهها مسألهی مهمی است تا مدل یک الگوی خاص از مجموعهی داده را یاد نگیرد. چون اگر مدل جزییات الگوی موجود در دادهها را یاد بگیرد نمیتوان آن را برای پیشبینی دادههای جدید و دیده نشده تعمیم داد. در واقع میخواهیم از بیشبرازش (over fitting) جلوگیری کنیم. بیشبرازش (over fitting) سبب میشود تا مدل روی دادههای آموزشی عملکرد بسیار خوبی داشته باشد. اما دادههای تست را با خطای بسیار بالا برچسبدهی کند.
Tensorflow این دو مسألهی تعداد مشاهدات مورد نیاز (Batchها یا همان تعداد تکرار) و همچنین تغییر داده را به خوبی مدیریت میکند. برای ساخت نحوهی فیددهی به مدل میتوان از pandas_input_fn استفاده کرد. این آبجکت (object) به 5 پارامتر نیاز دارد.
چون مدل در چندین مرحله آموزش مییابد، باید دادهها را به الگوریتم چندین بار فیددهی کنیم. برای این کار از تابع get_input_fn استفاده میکنیم تا پروسهی فیددهی دادهها را تکرار کند.
def get_input_fn(data_set, num_epochs=None, n_batch = 128, shuffle=True):
return tf.estimator.inputs.pandas_input_fn(
x=pd.DataFrame({k: data_set[k].values for k in FEATURES}),
y = pd.Series(data_set[LABEL].values),
batch_size=n_batch,
num_epochs=num_epochs,
shuffle=shuffle)
متد رایج ارزیابی کارایی مدل شامل موارد زیر است:
تخمینگر Tensorflow سه تابع مختلف را برای انجام این سه مرحله فراهم کرده و آن را بسیار ساده میسازد.
میتوان از estimator.train برای ارزیابی مدل استفاده کرد. train. estimator دو آرگومان ورودی دارد، یکی تابعی با عنوان input_fn و دیگری پارامتری با نام steps. میتوانید از تابعی که در مراحل قبلی با عنوان get_input_fn ساختهاید برای فیددهی استفاده کنید. سپس مدل را با تکرار 1000 مرتبه روی دادهها بسازید. توجه کنید که شما تعداد epochها رو تعیین نمیکنید و شما تنها مدل را 1000 مرتبه تکرار میکنید. اگر شما epoch را برابر یک تنظیم کنید، مدل 4 مرتبه تکرار میشود: چون 400 نمونه در مجموعه دادهی آموزشی دارید و اندازهی هر دسته (batch size) برابر 128 است. پس بهتر است epoch را None گذاشته و تعداد تکرار را تعیین کرد.
estimator.train(input_fn=get_input_fn(training_set,
num_epochs=None,
n_batch = 128,
shuffle=False),
steps=1000)
INFO:tensorflow:Calling model_fn. INFO:tensorflow:Done calling model_fn. INFO:tensorflow:Create CheckpointSaverHook. INFO:tensorflow:Graph was finalized. INFO:tensorflow:Running local_init_op. INFO:tensorflow:Done running local_init_op. INFO:tensorflow:Saving checkpoints for 1 into train/model.ckpt. INFO:tensorflow:loss = 83729.64, step = 1 INFO:tensorflow:global_step/sec: 238.616 INFO:tensorflow:loss = 13909.657, step = 101 (0.420 sec) INFO:tensorflow:global_step/sec: 314.293 INFO:tensorflow:loss = 12881.449, step = 201 (0.320 sec) INFO:tensorflow:global_step/sec: 303.863 INFO:tensorflow:loss = 12391.541, step = 301 (0.327 sec) INFO:tensorflow:global_step/sec: 308.782 INFO:tensorflow:loss = 12050.5625, step = 401 (0.326 sec) INFO:tensorflow:global_step/sec: 244.969 INFO:tensorflow:loss = 11766.134, step = 501 (0.407 sec) INFO:tensorflow:global_step/sec: 155.966 INFO:tensorflow:loss = 11509.922, step = 601 (0.641 sec) INFO:tensorflow:global_step/sec: 263.256 INFO:tensorflow:loss = 11272.889, step = 701 (0.379 sec) INFO:tensorflow:global_step/sec: 254.112 INFO:tensorflow:loss = 11051.9795, step = 801 (0.396 sec) INFO:tensorflow:global_step/sec: 292.405 INFO:tensorflow:loss = 10845.855, step = 901 (0.341 sec) INFO:tensorflow:Saving checkpoints for 1000 into train/model.ckpt. INFO:tensorflow:Loss for final step: 5925.9873.
میتوانید با دستور زیر گراف محاسباتی را در Tensorbord چک کنید.
# For Windows
tensorboard --logdir=train
با کد زیر میتوان مدل یاد گرفتهشده را روی دادهی تست fit کرد و به کار گرفت.
ev = estimator.evaluate(
input_fn=get_input_fn(test_set,
num_epochs=1,
n_batch = 128,
shuffle=False))
INFO:tensorflow:Calling model_fn. INFO:tensorflow:Done calling model_fn. INFO:tensorflow:Starting evaluation at 2018-05-13-01:43:13 INFO:tensorflow:Graph was finalized. INFO:tensorflow:Restoring parameters from train/model.ckpt-1000 INFO:tensorflow:Running local_init_op. INFO:tensorflow:Done running local_init_op. INFO:tensorflow:Finished evaluation at 2018-05-13-01:43:13 INFO:tensorflow:Saving dict for global step 1000: average_loss = 32.15896, global_step = 1000, loss = 3215.896
مقدار خطای مدل یا همان loss را با دستور زیر جداگانه میتوان چاپ کرد.
loss_score = ev["loss"]
print("Loss: {0:f}".format(loss_score))
Loss: 3215.895996
این مدل حدود ۳۰۰۰ خطا داشته است. برای بررسی میزان کم یا زیاد بودن خطای مدل حاصل، میتوانیم اطلاعات آماری دادههایمان را بررسی کنیم. به دستور زیر و خروجی آن توجه کنید:
training_set['medv'].describe()
count 400.000000 mean 22.625500 std 9.572593 min 5.000000 25% 16.600000 50% 21.400000 75% 25.025000 max 50.000000 Name: medv, dtype: float64
از اطلاعات آماری خلاصه شده در خروجی بالا، میتوان فهمید که میانگین قیمت خانه در دادههای آموزشی حدود 22 هزار تا است و این درحالی است که کمترین میزان قیمت 9 هزار تا و بیشترین میزان قیمت 50 هزار تا است. مدل ساخته شده هم، حدود سه هزار تا میتواند در تخمین قیمتها خطا داشته باشد.
درنهایت میتوانید از estimator.predict برای پیشبینی قیمت شش خانه در این مثال استفاده کنید.
y = estimator.predict(
input_fn=get_input_fn(prediction_set,
num_epochs=1,
n_batch = 128,
shuffle=False))
خروجی کد بالا را با دستور زیر چاپ کنید.
predictions = list(p["predictions"] for p in itertools.islice(y, 6))print("Predictions: {}".format(str(predictions)))
INFO:tensorflow:Calling model_fn. INFO:tensorflow:Done calling model_fn. INFO:tensorflow:Graph was finalized. INFO:tensorflow:Restoring parameters from train/model.ckpt-1000 INFO:tensorflow:Running local_init_op. INFO:tensorflow:Done running local_init_op. Predictions: [array([32.297546], dtype=float32), array([18.96125], dtype=float32), array([27.270979], dtype=float32), array([29.299236], dtype=float32), array([16.436684], dtype=float32), array([21.460876], dtype=float32)]
در این بخش به توضیح نحوهی حل مسأله تنها با استفاده از فریم ورک Tensorflow میپردازیم که کمی پیچیدهتر از روش قبلی است. توجه کنید که اگر از Jupyter notebook استفاده میکنید آن را Restart کرده و kernel را پاک کنید. در این بخش تابع input_fn را خودتان تعریف خواهیدکرد.
ابتدا دو متغیر را برای مسیر دادههای فایل csv تعیین میکنید. توجه داشته باشید که شما دو فایل csv دارید: یکی دادههای آموزشی و دیگری دادههای آزمایشی.
import tensorflow as tf
df_train = "E:/boston_train.csv"
df_eval = "E:/boston_test.csv"
سپس باید ستونهایی که نیاز دارید به کار ببرید را تعیین کنید که در این مثال ما همهی ستونها را به کارمیگیریم و همچنین نوع متغیرها را هم باید مشخص کرد. متغیرهای اعشاری را با [.0] تعریف میکنیم.
COLUMNS = ["crim", "zn", "indus", "nox", "rm", "age",
"dis", "tax", "ptratio", "medv"]RECORDS_ALL = [[0.0], [0.0], [0.0], [0.0],[0.0],[0.0],[0.0],[0.0],[0.0],[0.0]]
تابع میتواند به سه قسمت مساوی تقسیم شود:
کد در حالت کلی به شکل زیر تعریف میشود که توضیحات کد در ادامه آورده شده است.
def input_fn(data_file, batch_size, num_epoch = None):
# Step 1
def parse_csv(value):
columns = tf.decode_csv(value, record_defaults= RECORDS_ALL)
features = dict(zip(COLUMNS, columns))
#labels = features.pop('median_house_value')
labels = features.pop('medv')
return features, labels
# Extract lines from input files using the
Dataset API.
dataset = (tf.data.TextLineDataset(data_file) # Read text file
.skip(1) # Skip header row
.map(parse_csv))
dataset = dataset.repeat(num_epoch)
dataset = dataset.batch(batch_size)
# Step 3
iterator = dataset.make_one_shot_iterator()
features, labels = iterator.get_next()
return features, labels
1. وارد کردن داده
برای یک فایل csv، متد مجموعه داده در هر دفعه میتواند یک سطر را بخواند. برای ساخت مجموعه داده، نیاز به استفاده از آبجکت TextLineDataset داریم. مجموعه دادهی شما یک سرآیند (Header) دارد که شامل نام ویژگیها و برچسب دادهها است و در محاسبات استفاده نمیشود، پس خط اول را نمیخوانید. برای فیددهی به مدل ستون برچسب را از دادهها جدا میکنیم. از متد map برای تبدیل هرگونه داده استفاده میکنیم. این متد تابعی را فراخوانی میکند که شما برای ایجاد مبدل داده از آن استفاده خواهید کرد.
به طور خلاصه شما باید داده را به شیء TextLineDataset بدهید، سرآیند دادهها را حذف کنید و در نهایت یک تبدیل داده به کمک یک تابع انجام دهید:
(tf.data.TextLineDataset(data_file: این خط فایل csv را میخواند.
(skip(1. :سرآیند را رد کرده و درنظر نمیگیرد.
(map(parse_csv.: فایل csv را خوانده و به فرم تنسور تبدیل میکند. pars_csv فایل csv را با tf.decode_csv پیمایش کرده و ستونهای ویژگی و برچسب را تعیین میکند.
ویژگیها میتوانند به فرم دیکشنری یا تاپل باشند که فرم دیکشنری برای استفاده راحتتر است. توضیح کد:
(tf.decode_csv(value, record_defaults= RECORDS_ALL: متد decode_csv از خروجی TextLineDataset برای خواندن فایل csv استفاده میکند. record_defaults مرتبط به نوع دادهی ستونهاست.
مجموه داده در طول آموزش چندین مرتبه به تنسورها داده (فیددهی) میشود. پس باید متدی تعریف شود تا این فیددهی را به طور مکرر و نامحدود بتواند انجام دهد و اجرای برنامه با خطا مواجه نگردد. batch_size هم تعیین میکند که در هر مرتبه چه تعداد از دادههای مجموعه داده به پایپ لاین برای انجام محاسبات ارسال شود.
2. ایجاد iterator یا اشارهگر
هدف ساخت Iterator و یا اشارهگرهایی برای برگرداندن عناصر مجموعه داده است. سادهترین راه استفاده از make_one_shot_iterator است و پس از آن شما قادر به ایجاد کار کردن با ویژگیها و برچسب کلاس به کمک iterator خواهید بود.
3. استفاده از دادهها
برای اینکه بدانید چه اتفاقی در تابع input_fn رخ میدهد، میتوانید با بهکارگیری دادهها آن را کنترل کنید. این کار را با batch_size=1 انجام دهید. توجه کنید که قطعه کد زیر ویژگیها را به صورت دیکشنری و ستون برچسب را به شکل آرایه نمایش میدهد. اگر میخواهید در خروجی، سطرهای دیگر فایل csv مجموعه داده را ببینید میتوانید کد را با batch_sizeهای دیگر امتحان کنید.
next_batch = input_fn(df_train, batch_size = 1, num_epoch = None)
with tf.Session() as sess:
first_batch = sess.run(next_batch)
print(first_batch)
({'crim': array([2.3004], dtype=float32), 'zn': array([0.], dtype=float32), 'indus': array([19.58], dtype=float32), 'nox': array([0.605], dtype=float32), 'rm': array([6.319], dtype=float32), 'age': array([96.1], dtype=float32), 'dis': array([2.1], dtype=float32), 'tax': array([403.], dtype=float32), 'ptratio': array([14.7], dtype=float32)}, array([23.8], dtype=float32))
ویژگیهای عددی را به شکل زیر تعریف میکنیم:
X1= tf.feature_column.numeric_column('crim')
X2= tf.feature_column.numeric_column('zn')
X3= tf.feature_column.numeric_column('indus')
X4= tf.feature_column.numeric_column('nox')
X5= tf.feature_column.numeric_column('rm')
X6= tf.feature_column.numeric_column('age')
X7= tf.feature_column.numeric_column('dis')
X8= tf.feature_column.numeric_column('tax')
X9= tf.feature_column.numeric_column('ptratio')
توجه کنید که شما نیاز دارید تا تمام متغیرها را در یک براکت، به شکل زیر جمع کنید.
base_columns = [X1, X2, X3,X4, X5, X6,X7, X8, X9]
مدل را با تخمینگر رگرسیون خطی به شکل زیر آموزش میدهیم.
model = tf.estimator.LinearRegressor(feature_columns=base_columns, model_dir='train3')
INFO:tensorflow:Using default config. INFO:tensorflow:Using config: {'_model_dir': 'train3', '_tf_random_seed': None, '_save_summary_steps': 100, '_save_checkpoints_steps': None, '_save_checkpoints_secs': 600, '_session_config': None, '_keep_checkpoint_max': 5, '_keep_checkpoint_every_n_hours': 10000, '_log_step_count_steps': 100, '_train_distribute': None, '_service': None, '_cluster_spec': <tensorflow.python.training.server_lib.ClusterSpec object at 0x1820a010f0>, '_task_type': 'worker', '_task_id': 0, '_global_id_in_cluster': 0, '_master': '', '_evaluation_master': '', '_is_chief': True, '_num_ps_replicas': 0, '_num_worker_replicas': 1}
باید از تابع لامبدا برای نوشتن آرگومانهای داخل input_fn استفاده کرد و بدون لامبدا فانکشن قادر به آموزش مدل نخواهید بود.
# Train the estimatormodel.train(steps =1000,
input_fn= lambda : input_fn(df_train,batch_size=128, num_epoch = None))
INFO:tensorflow:Calling model_fn. INFO:tensorflow:Done calling model_fn. INFO:tensorflow:Create CheckpointSaverHook. INFO:tensorflow:Graph was finalized. INFO:tensorflow:Running local_init_op. INFO:tensorflow:Done running local_init_op. INFO:tensorflow:Saving checkpoints for 1 into train3/model.ckpt. INFO:tensorflow:loss = 83729.64, step = 1 INFO:tensorflow:global_step/sec: 72.5646 INFO:tensorflow:loss = 13909.657, step = 101 (1.380 sec) INFO:tensorflow:global_step/sec: 101.355 INFO:tensorflow:loss = 12881.449, step = 201 (0.986 sec) INFO:tensorflow:global_step/sec: 109.293 INFO:tensorflow:loss = 12391.541, step = 301 (0.915 sec) INFO:tensorflow:global_step/sec: 102.235 INFO:tensorflow:loss = 12050.5625, step = 401 (0.978 sec) INFO:tensorflow:global_step/sec: 104.656 INFO:tensorflow:loss = 11766.134, step = 501 (0.956 sec) INFO:tensorflow:global_step/sec: 106.697 INFO:tensorflow:loss = 11509.922, step = 601 (0.938 sec) INFO:tensorflow:global_step/sec: 118.454 INFO:tensorflow:loss = 11272.889, step = 701 (0.844 sec) INFO:tensorflow:global_step/sec: 114.947 INFO:tensorflow:loss = 11051.9795, step = 801 (0.870 sec) INFO:tensorflow:global_step/sec: 111.484 INFO:tensorflow:loss = 10845.855, step = 901 (0.897 sec) INFO:tensorflow:Saving checkpoints for 1000 into train3/model.ckpt. INFO:tensorflow:Loss for final step: 5925.9873. Out[8]: <tensorflow.python.estimator.canned.linear.LinearRegressor at 0x18225eb8d0>
مدل ایجاد شده را میتوان روی دادهی تست به شکل زیر به کار گرفت:
results = model.evaluate(steps =None,input_fn=lambda: input_fn(df_eval, batch_size =128, num_epoch = 1))
for key in results:
print(" {}, was: {}".format(key, results[key]))
INFO:tensorflow:Calling model_fn. INFO:tensorflow:Done calling model_fn. INFO:tensorflow:Starting evaluation at 2018-05-13-02:06:02 INFO:tensorflow:Graph was finalized. INFO:tensorflow:Restoring parameters from train3/model.ckpt-1000 INFO:tensorflow:Running local_init_op. INFO:tensorflow:Done running local_init_op. INFO:tensorflow:Finished evaluation at 2018-05-13-02:06:02 INFO:tensorflow:Saving dict for global step 1000: average_loss = 32.15896, global_step = 1000, loss = 3215.896 average_loss, was: 32.158958435058594 loss, was: 3215.89599609375 global_step, was: 1000
و اما در آخرین گام میخواهیم مقدار قیمت خانه را برای شش عضو مجموعهی Predict پیشبینی کنیم. چون که این مجموعه (Predict) ستون برچسب ندارد، پس یک تابع input_fn جدید برایش تعریف میکنیم. برای اینکار میتوان از API ی from_tensor موجود در Dataset استفاده کرد.
prediction_input = {
'crim': [0.03359,5.09017,0.12650,0.05515,8.15174,0.24522],
'zn': [75.0,0.0,25.0,33.0,0.0,0.0],
'indus': [2.95,18.10,5.13,2.18,18.10,9.90],
'nox': [0.428,0.713,0.453,0.472,0.700,0.544],
'rm': [7.024,6.297,6.762,7.236,5.390,5.782],
'age': [15.8,91.8,43.4,41.1,98.9,71.7],
'dis': [5.4011,2.3682,7.9809,4.0220,1.7281,4.0317],
'tax': [252,666,284,222,666,304],
'ptratio': [18.3,20.2,19.7,18.4,20.2,18.4]
}
def test_input_fn():
dataset = tf.data.Dataset.from_tensors(prediction_input)
return dataset
# Predict all our prediction_inputpred_results = model.predict(input_fn=test_input_fn)
مقدار پیشبینی شده را با دستور زیر میتوان چاپ کرد.
for pred in enumerate(pred_results):
print(pred)
INFO:tensorflow:Calling model_fn. INFO:tensorflow:Done calling model_fn. INFO:tensorflow:Graph was finalized. INFO:tensorflow:Restoring parameters from train3/model.ckpt-1000 INFO:tensorflow:Running local_init_op. INFO:tensorflow:Done running local_init_op. (0, {'predictions': array([32.297546], dtype=float32)}) (1, {'predictions': array([18.96125], dtype=float32)}) (2, {'predictions': array([27.270979], dtype=float32)}) (3, {'predictions': array([29.299236], dtype=float32)}) (4, {'predictions': array([16.436684], dtype=float32)}) (5, {'predictions': array([21.460876], dtype=float32)}) INFO:tensorflow:Calling model_fn. INFO:tensorflow:Done calling model_fn. INFO:tensorflow:Graph was finalized. INFO:tensorflow:Restoring parameters from train3/model.ckpt-5000 INFO:tensorflow:Running local_init_op. INFO:tensorflow:Done running local_init_op. (0, {'predictions': array([35.60663], dtype=float32)}) (1, {'predictions': array([22.298521], dtype=float32)}) (2, {'predictions': array([25.74533], dtype=float32)}) (3, {'predictions': array([35.126694], dtype=float32)}) (4, {'predictions': array([17.94416], dtype=float32)}) (5, {'predictions': array([22.606628], dtype=float32)})
به طور کلی مراحل زیر را برای اعمال یک مدل یادگیری ماشین درTensorFlow داریم:
تعریف ویژگیها یا همان متغیرهای مستقل: x
تعریف برچسب یا متغیر وابسته: y
ایجاد مجموعهی آموزشی و آزمایشی
تعریف وزنهای اولیه (در مثال ما ضرایب متغیرهای مستقل و بایاس)
تعریف تابع نقصان یا هزینه یا ضرر (در مثال ما MSE)
بهینهسازی مدل (همچون بکارگیری گرادیان کاهشی)
تعریف کردن:
نرخ یادگیری
تعداد epoch
اندازهی هر دسته یا batch_size
در این آموزش چگونگی به کارگرفتن API سطح بالا برای رگرسیون خطی تشریح شد. دیدیم که باید موارد زیر را برای این منظور تعریف کنیم:
تعریف ستونهای ویژگی: ()feature_column.numeric_column
بهکارگیری تخمینگر: (estimator.LinearRegressor(feature_columns, model_dir
تابعی برای وارد کردن داده و اندازهی دستهها و تعداد مراحل: ()input_fn
و در آخر قادر به آموزش (train)، ارزیابی (evaluate) و پیشبینی (predict) خواهید بود.
در مقالهی آموزش TensorFlow با فریم ورک تنسورفلو به طور کلی آشنا شدیم. مفاهیم آن را بررسی کردیم، مثالهای سادهای برای درک بهتر موضوع، کدزنی کردیم و در پایان چگونگی آموزش یک مدل برمبنای رگرسیون خطی در تنسورفلو را هم دیدیم. اگر در مورد این مقاله سوال یا نظری داشتید خوشحال میشویم که در بخش نظرات با ما و کاربران سون لرن به اشتراک بگذارید.
اگر دوست داری به یک متخصص داده کاوی اطلاعات با زبان پایتون تبدیل شوی و با استفاده از آن در بزرگترین شرکتها مشغول به کار شوی، شرکت در دوره جامع آموزش پایتون را پیشنهاد میکنیم.
سلام ممنون از انتخاب و انتشار ترجمه ولی لطفا حرفه ای باشید . لطفا در ابتدای متن آدرس متن اصلی را ارائه کنید. رعایت قوانین کپی رایت مطمئنا به نفع شما و به نفع جامعه برنامه نویسی هست. به علاوه حسن ظن زیادی نسبت به شما به عنوان یک متخصص ایجاد خواهد کرد. باز هم ممنون از اینکه زحمت میکشید و این متنهای خوب را پیدا و منتشر میکنید.
سلام ببخشید یک سوالی دارم تنسور فلو در پایتون رو میشه به فایل جاوا اسکریپت تبدیل کرد؟
درود بله با یسری کتابخونه مثل <a href="https://github.com/tensorflow/tfjs" target="_blank" rel="noopener nofollow ugc">tfjs </a>قابل انجام هست.
درود باید سرفصلهای دوره متخصص علوم داده رو بررسی کنید اگر آموزشی باشه اونجاست. تنسور فلو 2 دارای یسری تغییر خیلی خوب هست که کار رو راحت میکنه. برای مثال تو نسخه دوم ما نمودارهای داینامیک داریم، به استفاده از مفهوم Session نیازی نیست و از توابع استفاده میشه. همچنین کراس به صورت ماژول در کد ایمپورت و استفاده میشه.
عالی بود دستتون درد نکنه . مورد جالبی دیگه بهش برخوردم که خیلی خوشحالم کرد این بود که TensorFlow کتابخونه برای جاوااسکریپت ( زبان مورد علاقه م ) هم داره . در کل ممنون بابت بابت مقاله پر محتوا و عالی تون.
متشکرم. خوشحالم که براتون مفید بوده. بله همینطوره. بسیاری از کتابخانههای پایتون هستند که این ویژگی رو دارند و حالا این یا به خاطر الگوبرداری از زبانهای دیگر و تکمیل اون درمجموعه کتابخانههای خودشه و بالعکس . و یا بخاطر هماهنگی برای کار با سایرزبانها که هریک ویژگی کاربردی خودشون رو دارن.