آموزشیادگیری ماشین

درس ۹۱ از ۹۹، هوش مصنوعی، حدود ۳۴ دقیقه خواندن

اولین پروژه‌ی کامل: از فایل داده تا پیش‌بینی

جواب کوتاه

یه پروژه‌ی یادگیری ماشین، هر چقدر هم بزرگ، تقریبا همیشه همین شش قدم رو داره: فایل داده رو می‌خونیم، ردیف‌های خراب رو کنار می‌ذاریم، داده رو دو دسته می‌کنیم که یه دسته برای آموزش باشه و یکی برای آزمون، مدل رو روی دسته‌ی آموزش آموزش می‌دیم، روی دسته‌ی آزمون می‌سنجیم و با یه خط پایه مقایسه‌ش می‌کنیم، و آخر سر برای یه ورودی تازه پیش‌بینی می‌گیریم. این درس همه‌ی این شش قدم رو با یه مثال واقعی، ساعت درس خوندن و نمره، و فقط با خود پایتون، از اول تا آخر می‌ره.

مسئله

فرض کنید یه معلم یه فایل داره: هر کدوم از بچه‌ها چند ساعت برای امتحان درس خونده و چند گرفته. می‌خوایم بفهمیم کسی که چهار ساعت و نیم بخونه، احتمالا چند می‌گیره.

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

کل راه همین شش ایستگاهه. پروژه‌های خیلی بزرگ هم، با میلیون‌ها ردیف و مدل‌های پیچیده، همین شش قدم رو دارن؛ فقط هر قدمشون مفصل‌تره. برای اینکه هیچ چیزی لازم نباشه نصب کنید، همه‌ی کد رو فقط با خود پایتون و ابزارهایی که همراهش میاد می‌نویسیم. اگه درس پایتون رو خوندید، همه‌ی خط‌ها رو می‌فهمید؛ هر جا هم چیز تازه‌ای اومد، همون‌جا توضیحش می‌دم.

فایل داده

داده‌ی ما یه فایل ساده‌ست به اسم scores.csv. این مدل فایل‌ها رو هر برنامه‌ی جدولی می‌تونه بسازه و باز کنه، و رایج‌ترین شکل داده‌ای هست که توی پروژه‌ها می‌بینید. توش این ۱۳ تا ردیفه:

hours,score
1,8
2,9
2,11
3,12
3,
4,12
...

اگه فایل رو با یه ویرایشگر متن باز کنید، این شکلیه. خط اول اسم ستون‌هاست، hours یعنی ساعت و score یعنی نمره. هر خط بعدی یه نفره، و دو تا عددش با ویرگول از هم جدا شدن. اسم این مدل فایل هم از همین میاد: «عددهایی که با ویرگول جدا شدن».

قبل از هر کاری، به داده نگاه کنید. همین نگاه ساده دو تا چیز رو نشون می‌ده. اول اینکه هر چی ساعت بیشتر شده، نمره هم کم‌وبیش بیشتر شده؛ یعنی یه خط احتمالا به درد می‌خوره. دوم اینکه یه ردیف نمره نداره. شاید اون بچه غایب بوده، شاید معلم یادش رفته بنویسه. داده‌ی واقعی تقریبا همیشه از این خرابی‌ها داره.

ستون ساعت این‌جا ویژگی هست، یعنی چیزی که از قبل می‌دونیم، و ستون نمره برچسب، یعنی چیزی که می‌خوایم حدس بزنیم. همون دو تا کلمه‌ای که توی درس ویژگی و برچسب دیدیم.

خوندن و تمیز کردن

قدم اول اینه که فایل رو بخونیم و ردیف خالی رو کنار بذاریم. توی دفترچه‌ی کد، این چند خط رو توی یه خونه بنویسید:

import csv

rows = []
with open("scores.csv") as f:
    for r in csv.DictReader(f):
        if r["score"] == "":
            continue
        rows.append((float(r["hours"]), float(r["score"])))

len(rows)   # 12

خط اول ابزار خوندن این مدل فایل‌ها رو میاره، که همراه خود پایتونه. بعد یه فهرست خالی به اسم rows می‌سازیم که ردیف‌های سالم رو توش جمع کنیم.

خط with open یعنی «فایل رو باز کن، اسمش رو بذار f، و تا آخر این بلوک بازش نگه دار». بعد یه حلقه روی ردیف‌های فایل داریم. ابزاری که آوردیم هر ردیف رو طوری بهمون می‌ده که با اسم ستون بشه سراغش رفت؛ یعنی r["score"] نمره‌ی همون ردیفه.

حالا شرط: اگه نمره خالیه، continue، یعنی بقیه‌ی این دور رو ول کن و برو سراغ ردیف بعد. وگرنه، ساعت و نمره رو به صورت یه جفت به فهرست اضافه می‌کنیم. اون float هم خیلی مهمه. هر چی از فایل خونده می‌شه، اولش متنه، حتی اگه شکل عدد باشه؛ float اون متن رو تبدیل می‌کنه به عدد، تا بشه باهاش حساب کرد.

آخرش len(rows) می‌گه ۱۲. یعنی از ۱۳ تا ردیف، یکی کنار رفت و دوازده تا موند. همیشه بعد از تمیز کردن یه بار بشمرید؛ اگه دیدید نصف داده‌تون غیب شده، یعنی یه جای کار ایراد داره.

با ردیف بی نمره چی کار کنیم؟

اون ردیف ۳ ساعت که نمره نداشت رو کنار گذاشتیم. دو تا راه دیگه هم بود. می‌شد جای خالیش رو با میانگین نمره‌ها پر کنیم، که ۱۳٫۵۸ هست؛ ولی این یعنی یه نمره‌ی ساختگی بذاریم که برای ۳ ساعت درس خیلی زیاده، چون بقیه‌ی ۳ ساعتی‌ها حدود ۱۲ گرفتن، و خط رو یه کم به سمت خودش می‌کشه. یا می‌شد با خود مدل حدسش بزنیم، ولی اون‌وقت داریم مدل رو با حدس خودش آموزش می‌دیم و چیز تازه‌ای یاد نمی‌گیره.

وقتی ستونی که می‌خوایم پیش‌بینیش کنیم خالیه، تقریبا همیشه بهترین کار کنار گذاشتن اون ردیفه. ولی اگه یکی از ستون‌های ورودی خالی بود، مثلا ساعت خواب، و ردیف‌های خالی زیاد بودن، پر کردن با میانگین یا میانه می‌تونه بهتر از دور ریختن نصف داده باشه. همیشه هم قبلش بپرسید چرا خالیه؛ اگه کسایی که نمره‌ی بد گرفتن نمره‌شون رو ننوشتن، با کنار گذاشتنشون، داده رو خوش‌بین‌تر از واقعیت کردید.

دو دسته

قبل از آموزش، یه کار خیلی مهم: چند تا از ردیف‌ها رو کنار می‌ذاریم که مدل هیچ‌وقت نبینه‌شون، تا آخر کار باهاشون امتحانش کنیم.

import random

random.seed(1)
random.shuffle(rows)
train = rows[:9]
test = rows[9:]

shuffle فهرست رو مثل یه دست ورق به‌هم می‌زنه. چرا؟ چون ردیف‌های فایل به ترتیب ساعت مرتب بودن، و اگه همین‌جوری سه تای آخر رو برمی‌داشتیم، همه‌ی آزمون‌ها مال کسایی می‌شد که زیاد خوندن. به‌هم زدن باعث می‌شه هر دو دسته شبیه کل داده باشن.

seed یه عدد شروع برای این شانس می‌ده؛ با همون عدد، هر بار دقیقا همین ترتیب درمیاد. این برای اینه که شما هم اگه این کد رو اجرا کنید، همین عددهای این درس رو ببینید.

بعد با rows[:9] نه تای اول رو برمی‌داریم برای آموزش، و با rows[9:] بقیه رو، یعنی سه تا، برای آزمون. اون دونقطه توی کروشه یعنی «یه تیکه از فهرست»: قبلش هیچی ننوشتیم یعنی از اول، بعدش هیچی ننوشتیم یعنی تا آخر.

چرا این‌قدر مهمه؟ چون مدل روی داده‌ای که دیده، همیشه خوب به نظر میاد. سوال واقعی اینه که روی کسی که ندیده چقدر خوبه؛ همون چیزی که توی درس داده‌ی آموزش و آزمون دیدیم. توی این مثال داده خیلی کمه و سه تا آزمون فقط یه حدس اولیه می‌ده؛ توی پروژه‌ی واقعی داده خیلی بیشتره و دسته‌ی آزمون هم بزرگ‌تر.

آموزش

حالا خود مدل. مدل ما یه خطه، و آموزش یعنی پیدا کردن بهترین خطی که از بین این نه تا نقطه رد می‌شه:

import statistics

x = [h for h, s in train]
y = [s for h, s in train]
slope, intercept = statistics.linear_regression(x, y)

slope, intercept   # 1.52, 6.74

دو خط اول، دو تا فهرست جدا می‌سازن: یکی فقط ساعت‌ها و یکی فقط نمره‌ها. این مدل نوشتن یه میون‌بر پایتونه؛ بخونیدش «یه فهرست بساز از h، برای هر جفت h و s توی train». همون کار یه حلقه رو توی یه خط می‌کنه.

خط بعد کار اصلیه. ابزار آمار خود پایتون یه تابع داره که از روی دو تا فهرست، بهترین خط رو پیدا می‌کنه. «بهترین» یعنی خطی که میانگین مربع خطایش از همه کمتره؛ همون چیزی که توی درس‌های ایستگاه ۴ دیدیم. دو تا عدد پس می‌ده: شیب، که می‌گه هر ساعت بیشتر درس خوندن چقدر به نمره اضافه می‌کنه، و عرض از مبدا، که می‌گه خط از کجا شروع می‌شه.

جواب: شیب حدود ۱٫۵۲ و عرض از مبدا حدود ۶٫۷۴. یعنی مدل ما می‌گه «نمره تقریبا برابره با ۱٫۵۲ ضرب در ساعت، به اضافه‌ی ۶٫۷۴». همین دو تا عدد، کل چیزیه که مدل یاد گرفته. توی درس مدل و پارامتر گفتیم که پارامترها همون عددهایی‌ان که از داده یاد گرفته می‌شن؛ این‌جا دو تا داریم. یه شبکه‌ی عصبی بزرگ هم همینه، فقط به جای دو تا، میلیون‌ها عدد.

پشت اون تابع آماده

اون linear_regression جادو نمی‌کنه؛ یه فرمول ساده‌ست که می‌شه با دست هم حسابش کرد. اول میانگین ساعت‌های آموزش رو می‌گیریم، که ۴٫۷۸ هست، و میانگین نمره‌ها، که دقیقا ۱۴ هست. بعد برای هر ردیف می‌پرسیم ساعتش چقدر از میانگین دوره و نمره‌ش چقدر. اگه ردیف‌هایی که ساعت بیشتری دارن، نمره‌ی بیشتری هم دارن، این دو تا فاصله با هم هم‌جهت‌ان.

شیب می‌شه جمع «فاصله‌ی ساعت ضرب در فاصله‌ی نمره» برای همه‌ی ردیف‌ها، تقسیم بر جمع «فاصله‌ی ساعت به توان دو». این‌جا درمیاد ۱٫۵۲. بعد عرض از مبدا جوریه که خط از نقطه‌ی میانگین‌ها رد بشه: ۱۴ منهای ۱٫۵۲ ضرب در ۴٫۷۸، که می‌شه ۶٫۷۴. همون دو عددی که تابع آماده داد. به این روش می‌گن کمترین مربعات، چون خطی رو پیدا می‌کنه که جمع مربع فاصله‌ی نقطه‌ها ازش کمترین باشه. توی درس چرا پایتون همین فرمول رو خط به خط نوشتیم.

سنجش

حالا وقتشه که اون سه تا ردیفی که کنار گذاشتیم رو بیاریم. برای هر کدوم، مدل حدس می‌زنه و ما فاصله‌ی حدس با نمره‌ی واقعی رو حساب می‌کنیم:

errors = []
for h, s in test:
    guess = slope * h + intercept
    errors.append(abs(guess - s))

statistics.mean(errors)   # 1.05

برای هر ردیف آزمون، حدس مدل رو حساب می‌کنیم و اختلافش با نمره‌ی واقعی رو برمی‌داریم. abs علامت منفی رو برمی‌داره، چون برامون مهم نیست مدل بیشتر حدس زده یا کمتر، فقط مهمه چقدر دور بوده. آخرش میانگین این خطاها رو می‌گیریم. اسم این عدد «میانگین خطای مطلق» هست که توی درس سنجش مدل عددی دیدیم.

جواب ۱٫۰۵ شد؛ یعنی مدل ما به‌طور میانگین حدود یک نمره اشتباه می‌کنه. خوبه یا بد؟ این عدد تنها هیچی نمی‌گه. باید ببینیم یه حدس خیلی ساده، بدون هیچ یادگیری‌ای، چقدر اشتباه می‌کرد:

base = statistics.mean(y)   # 14.0
statistics.mean([abs(base - s) for h, s in test])   # 3.67

این‌جا به جای مدل، همیشه میانگین نمره‌های آموزش رو حدس زدیم، که ۱۴ بود؛ یعنی «هر کی هر چقدر خونده، می‌گیم ۱۴». خطای این حدس ساده ۳٫۶۷ شد. به این می‌گن خط پایه. حالا عدد ما معنی پیدا می‌کنه: مدلمون خطا رو تقریبا به یک سوم رسونده. اگه مدلی از خط پایه بهتر نباشه، یعنی هیچی یاد نگرفته، هر چقدر هم پیچیده باشه.

دو عدد مدل چی می‌گن؟

شیب ۱٫۵۲ یعنی توی این داده، هر ساعت درس بیشتر، به‌طور میانگین حدود یک و نیم نمره بیشتر همراهشه. عرض از مبدا ۶٫۷۴ یعنی حدس خط برای کسی که صفر ساعت خونده؛ ولی کسی توی داده‌ی ما کمتر از یه ساعت نخونده، پس این عدد بیشتر یه تیکه‌ی لازم برای کشیدن خطه تا یه حرف قابل اعتماد درباره‌ی آدم‌هایی که اصلا درس نخوندن.

ساعت و نمره توی این ۱۲ ردیف خیلی با هم بالا پایین می‌رن؛ همبستگیشون ۰٫۹۶۴ هست، نزدیک یک. ولی یه نکته‌ی خیلی مهم: این داده نمی‌گه «درس خوندن باعث نمره‌ی بهتر می‌شه»، فقط می‌گه این دو تا با هم میان. شاید کسایی که بیشتر درس خوندن، از اول هم علاقه‌ی بیشتری داشتن، و علاقه هر دو رو بالا برده. برای گفتن «علت»، باید آزمایش کرد؛ مثلا به دو گروه شبیه، به یکی بگیم بیشتر بخونه و ببینیم چی می‌شه. مدل یادگیری ماشین معمولا فقط «با هم اومدن» رو یاد می‌گیره، و برای پیش‌بینی همین کافیه؛ ولی برای تصمیم گرفتن که «چی رو عوض کنیم»، کافی نیست.

یه چیز دیگه درباره‌ی سنجش. ما میانگین قدر مطلق خطا رو گرفتیم: سه تا خطای آزمون ۰٫۷۸، منفی ۱٫۱۴ و منفی ۱٫۲۲ بودن، و میانگین اندازه‌شون ۱٫۰۵. یه اندازه‌ی رایج دیگه اینه که هر خطا رو به توان دو برسونیم، میانگین بگیریم و جذرش رو بگیریم؛ این‌جا می‌شه ۱٫۰۶. فرقشون اینه که دومی خطاهای بزرگ رو بیشتر جریمه می‌کنه؛ اگه یه پیش‌بینی خیلی دور باشه، عدد دومی خیلی بیشتر از اولی بالا می‌ره. وقتی هر دو نزدیک همن، مثل این‌جا، یعنی خطای خیلی بزرگی نداشتیم.

خط کجا اشتباه کرد؟

قبل از اینکه سراغ آزمون بریم، یه نگاه به خود داده‌ی آموزش بندازیم. خط از کنار هر نقطه چقدر رد شده؟

به این فاصله‌ها می‌گن باقی‌مونده؛ یعنی چیزی که خط نتونست توضیح بده. روی همین ۹ ردیف آموزش، میانگینش ۰٫۷۳ هست. ولی یادتون باشه، روی آزمون ۱٫۰۵ بود. چرا آزمون بدتره؟ چون خط با همین ۹ نقطه ساخته شده و تا جای ممکن به اون‌ها نزدیک شده؛ ولی سه ردیف آزمون رو هیچ‌وقت ندیده. همیشه همین‌طوره: نمره‌ی یه مدل روی داده‌ی خودش، از واقعیت خوش‌بینانه‌تره، و برای همین فقط عدد آزمون رو باور می‌کنیم.

یه چیز دیگه هم از باقی‌مونده‌ها می‌شه فهمید. اگه همه‌شون شانسی بالا و پایین خط باشن، خط کارش رو کرده. ولی اگه مثلا همه‌ی نقطه‌های وسط بالای خط باشن و دو سر پایین، یعنی داده یه انحنا داره که خط صاف نمی‌بینه. این‌جا بالا پایین شانسیه؛ بزرگ‌ترینش مال ردیف ۵ ساعت و نمره‌ی ۱۳ هست، که ۱٫۳ زیر خطه، و کنارش ردیف ۵ ساعت و ۱۵ بالای خط. یعنی دو نفر با یه اندازه درس، دو نمره‌ی مختلف گرفتن؛ این چیزیه که هیچ خطی نمی‌تونه بگیره، و طبیعیه.

یه بار شانس، یا واقعا خوب؟

خطای ۱٫۰۵ روی آزمون رو با یه بار به‌هم زدن، با seed(1)، گرفتیم. اگه یه جور دیگه به‌هم می‌زدیم چی؟ همین کار رو ده بار، با seedهای ۱ تا ۱۰، تکرار کردیم:

import csv, random, statistics

rows = []
with open("scores.csv") as f:
    for r in csv.DictReader(f):
        if r["score"] == "":
            continue
        rows.append((float(r["hours"]), float(r["score"])))

def test_error(seed):
    data = rows[:]
    random.seed(seed)
    random.shuffle(data)
    train, test = data[:9], data[9:]
    slope, icpt = statistics.linear_regression([h for h, s in train], [s for h, s in train])
    return statistics.mean(abs(slope * h + icpt - s) for h, s in test)

errs = [test_error(seed) for seed in range(1, 11)]
print([round(e, 2) for e in errs])
print("min", round(min(errs), 2), "max", round(max(errs), 2))
[1.05, 1.13, 0.89, 0.88, 1.06, 0.96, 1.36, 1.09, 1.17, 1.05]
min 0.88 max 1.36

همون داده، همون روش، و خطا از ۰٫۸۸ تا ۱٫۳۶. یعنی اگه یه نفر فقط seed هفت رو می‌دید، فکر می‌کرد مدلش بدتره، و یکی دیگه با seed چهار فکر می‌کرد بهتره. فرق اینا مال مدل نیست؛ مال اینه که کدوم سه نفر توی آزمون افتادن. وقتی آزمون فقط سه ردیفه، یه ردیف عجیب کل عدد رو جابه‌جا می‌کنه.

یکی‌یکی کنار بذاریم

یه راه بهتر برای داده‌ی کم: هر بار فقط یه ردیف رو کنار بذاریم، خط رو با ۱۱ تای دیگه بسازیم، و خطا رو روی همون یکی بسنجیم. ۱۲ بار، برای هر ردیف یه بار. این‌جوری هر ردیف دقیقا یه بار آزمون می‌شه و هیچ شانسی توی کار نیست:

import csv, statistics

rows = []
with open("scores.csv") as f:
    for r in csv.DictReader(f):
        if r["score"] == "":
            continue
        rows.append((float(r["hours"]), float(r["score"])))

errors = []
for i in range(len(rows)):
    train = rows[:i] + rows[i + 1:]       # all but one
    h, s = rows[i]                        # the one left out
    slope, icpt = statistics.linear_regression([a for a, b in train], [b for a, b in train])
    errors.append(abs(slope * h + icpt - s))
print(round(statistics.mean(errors), 2))
print(max(errors), rows[errors.index(max(errors))])
0.92
1.6241007194244617 (5.0, 13.0)

میانگین خطا ۰٫۹۲. این عدد از اون ۱٫۰۵ قابل اعتمادتره، چون از ۱۲ آزمون اومده، نه سه تا. و بدترین ردیف، باز همون ۵ ساعت و نمره‌ی ۱۳ بود، با خطای ۱٫۶۲. به این روش می‌گن یکی‌یکی کنار گذاشتن، و شکل کلیش، که داده رو به چند تیکه تقسیم می‌کنه، همون اعتبارسنجی متقابله. برای داده‌ی بزرگ، یکی‌یکی کنار گذاشتن خیلی کند می‌شه، چون باید به تعداد ردیف‌ها مدل بسازید؛ اون‌جا معمولا پنج یا ده تیکه کافیه.

پیش‌بینی

و حالا جواب سوال اولمون. کسی که چهار ساعت و نیم بخونه چند می‌گیره؟

slope * 4.5 + intercept   # 13.6
slope * 9 + intercept     # 20.4

برای چهار ساعت و نیم، مدل می‌گه حدود ۱۳٫۶. این همون کاریه که یه مدل یادگیری ماشین آخرش انجام می‌ده: یه ورودی تازه که هیچ‌وقت ندیده، و یه حدس که از روی الگوی داده‌ها ساخته.

ولی خط دوم رو نگاه کنید. برای کسی که ۹ ساعت بخونه، مدل می‌گه ۲۰٫۴؛ بیشتر از ۲۰! نمره که بیشتر از ۲۰ نمی‌شه. چی شد؟ مدل ما فقط یه خطه و نمی‌دونه نمره سقف داره. توی داده‌ش هم کسی بیشتر از ۸ ساعت نخونده بود، پس هیچ‌وقت ندیده بعد از اون چه اتفاقی می‌افته.

این یکی از مهم‌ترین درس‌های این پروژه‌ست: مدل فقط توی محدوده‌ای که داده دیده قابل اعتماده. بیرون از اون محدوده، فقط داره خطش رو ادامه می‌ده، بدون اینکه بدونه دنیای واقعی اون‌جا چه شکلیه. هر جا مدلی دیدید که برای چیزی خیلی متفاوت از داده‌ش جواب می‌ده، همین رو یادتون باشه.

نگه داشتن مدل

مدل ما آخرش فقط دو تا عدده: شیب و عرض از مبدا. لازم نیست هر بار از اول آموزشش بدیم؛ همین دو تا عدد رو توی یه فایل می‌نویسیم و هر وقت لازم شد می‌خونیم. یه چیز دیگه هم دیدیم: ۹ ساعت درس، نمره‌ی ۲۰٫۴ می‌گرفت، که از سقف ۲۰ بیشتره. این رو هم موقع پیش‌بینی درست می‌کنیم:

import json

model = {"slope": 1.51875, "intercept": 6.74375}
with open("model.json", "w") as f:
    json.dump(model, f)

# later, in another program:
with open("model.json") as f:
    m = json.load(f)

def predict(hours):
    guess = m["slope"] * hours + m["intercept"]
    return max(0, min(20, guess))      # a score is between 0 and 20

print(open("model.json").read())
print(predict(4.5), predict(9))
{"slope": 1.51875, "intercept": 6.74375}
13.578125 20

فایل model.json یه فایل متنی ساده‌ست که دقیقا همون دو عدد توشه. JSON، کوتاه‌شده‌ی JavaScript Object Notation، یعنی «نشانه‌گذاری شیء جاوااسکریپت»، شکلی از نوشتن داده‌ست که هم آدم می‌خونه و هم تقریبا همه‌ی زبان‌ها؛ و دقیقا شبیه دیکشنری پایتونه. بعد تابع predict جواب رو بین صفر و ۲۰ نگه می‌داره؛ ۴٫۵ ساعت هنوز ۱۳٫۶ می‌ده، ولی ۹ ساعت دیگه ۲۰ می‌ده، نه ۲۰٫۴.

مدل‌های بزرگ هم دقیقا همین‌طور ذخیره می‌شن؛ فقط به‌جای دو عدد، میلیون‌ها یا میلیاردها عدد. و این قانون که «جواب باید توی بازه‌ی معقول باشه» رو همیشه خودتون اضافه کنید؛ مدل خودش از نمره‌ی ۲۰ چیزی نمی‌دونه.

اشتباه‌های رایج

رایج‌ترینش سنجیدن مدل روی همون داده‌ای که باهاش آموزش دیده؛ دیدیم که ۰٫۷۳ از ۱٫۰۵ خوش‌بینانه‌تره. بعدی به‌هم نزدن داده قبل از تقسیم؛ اگه فایل به ترتیب ساعت مرتب باشه و سه ردیف آخر رو آزمون کنید، فقط آدم‌های پرساعت آزمون می‌شن. بعدی باور کردن یه بار تقسیم با داده‌ی کم. بعدی پیش‌بینی خیلی بیرون از داده؛ کسی توی داده‌ی ما بیشتر از ۸ ساعت درس نخونده، پس درباره‌ی ۱۵ ساعت خط هیچ چیزی نمی‌دونه. و آخری، مقایسه نکردن با خط پایه؛ عدد ۱٫۰۵ به‌تنهایی معنی نداره، کنار ۳٫۶۷ معنی پیدا می‌کنه.

این روش‌ها خیلی قدیمی‌ان. آدرین ماری لژاندر سال ۱۸۰۵ کمترین مربعات رو منتشر کرد و کارل فریدریش گاوس سال ۱۸۰۹ نوشت که از سال‌ها قبل ازش استفاده می‌کرده؛ مثلا برای پیش‌بینی جای یه سیاره‌ی کوچیک. و مروین استون سال ۱۹۷۴ اعتبارسنجی متقابل رو به شکل امروزیش نوشت. پس اولین پروژه‌ی شما، با ابزارهایی ساخته شده که بیشتر از دویست سال امتحانشون رو پس دادن.

قدم بعد

تبریک! همین حالا یه پروژه‌ی کامل یادگیری ماشین رو از اول تا آخر رفتید: کل کدش کمتر از سی خطه. پروژه‌های بزرگ‌تر همین اسکلت رو دارن، فقط هر تیکه‌ش رو بیشتر می‌کنن. چند تا راه برای بهتر کردن همین پروژه:

اول از همه، داده‌ی بیشتر؛ دیدیم با ۱۲ ردیف هر عددی که درمیاد شکننده‌ست، و با صد ردیف هم خط مطمئن‌تره هم آزمون معنی‌دارتر. بعد ویژگی بیشتر؛ نمره فقط به ساعت درس بستگی نداره، و مثلا ساعت خواب شب قبل امتحان هم می‌تونه یه ستون باشه، که همون مهندسی ویژگی هست. بعد سنجش مطمئن‌تر، که بالاتر یه نمونه‌ش رو با یکی‌یکی کنار گذاشتن دیدیم و اسم کلیش اعتبارسنجی متقابل هست. و آخر، مدل دیگه؛ اگه خط کافی نبود، کتابخونه‌های رایگان یادگیری ماشین ده‌ها مدل آماده دارن، مثلدرخت تصمیم، و شش قدم همون می‌مونه، فقط خط آموزش عوض می‌شه.

توی این پروژه، پیدا کردن خط رو سپردیم به یه تابع آماده. درس بعد همون کار رو خودمون، بی هیچ ابزار آماده‌ای، با گرادیان کاهشی انجام می‌دیم، و بعد یه شبکه‌ی کوچیک می‌سازیم: گرادیان کاهشی و شبکه‌ی کوچک بی کتابخونه.

جمع‌بندی. آنچه از این درس با خودتان می‌برید.

  • شش قدم: خوندن، تمیز کردن، دو دسته، آموزش، سنجش، پیش‌بینی.
  • ردیف خالی رو کنار بذارید؛ متن فایل رو عدد کنید.
  • دسته‌ی آزمون رو مدل هیچ‌وقت نباید ببینه.
  • عدد خطا تنها معنی نداره؛ با خط پایه مقایسه‌ش کنید.
  • بیرون از محدوده‌ی داده، به پیش‌بینی اعتماد نکنید.

خودتون رو بسنجید

۱۵ پرسش، هر بار تازه از میان ۳۰ پرسش این درس. آخرش فقط کارنامه رو می‌بینید: چند تا درست، چند تا نادرست.

خودتون رو بسنجید

۱۵ پرسش

  • هر بار پرسش‌ها و ترتیب گزینه‌ها عوض می‌شه.
  • تا آخر نمی‌گیم کدوم جواب درست بوده؛ می‌تونید برگردید و جوابتون رو عوض کنید.
  • آخرش کارنامه می‌گیرید: چند تا درست، چند تا نادرست.
  • اگه وسطش بستید، دوباره که باز کنید از همون‌جا ادامه می‌دید.

فصل‌های این درس

درس بعد