گام به گام اولین شبکه عصبی خود را با PyTorch توسعه دهید

بارگذاری داده در پایتورچ
آگوست 22, 2023
بینایی ماشین با پایتورچ
آگوست 24, 2023

گام به گام اولین شبکه عصبی خود را با PyTorch توسعه دهید

PyTorch یک کتابخانه قدرتمند پایتون برای ساخت مدل های یادگیری عمیق است. هر آنچه برای تعریف و آموزش شبکه عصبی و استفاده از آن برای استنتاج نیاز دارید را فراهم می کند. برای تکمیل همه اینها نیازی به نوشتن کد زیادی ندارید. در این پست نحوه ایجاد اولین مدل شبکه عصبی یادگیری عمیق خود را در پایتون با استفاده از PyTorch خواهید فهمید. پس از تکمیل این پست موارد زیر را یاد می گیرید:

چگونه یک مجموعه داده CSV را بارگیری کنیم و آن را برای استفاده با PyTorch آماده کنیم
چگونه یک مدل پرسپترون چند لایه را در PyToch تعریف کنیم
نحوه آموزش و ارزیابی یک مدل PyToch بر روی مجموعه داده اعتبارسنجی

بررسی اجمالی

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

  • بارگذاری داده ها
  • تعریف مدل PyToch
  • تعریف Loss Function و Optimizers
  • اجرای یک حلقه آموزشی
  • ارزیابی مدل
  • ایجاد پیش بینی

بارگذاری داده ها

اولین قدم این است که توابع و کلاس هایی را که می خواهید در این پست استفاده کنید، تعریف کنید. شما از کتابخانه NumPy برای بارگذاری مجموعه داده خود و کتابخانه PyTorch برای مدل های یادگیری عمیق استفاده خواهید کرد.

ورودی های مورد نیاز به شرح زیر است:

import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim

در این پست، از مجموعه داده دیابت Pima Indians استفاده خواهیم کرد. این یک مجموعه داده استاندارد یادگیری ماشین است. این مجموعه داده, اطلاعات سوابق پزشکی بیماران Pima Indians است و اینکه آیا آنها در طی پنج سال به دیابت مبتلا شده اند یا خیر، را توضیح می دهد.

این یک مسئله طبقه بندی باینری است (شروع دیابت به عنوان 1 یا نه به عنوان 0). تمام متغیرهای ورودی که هر بیمار را توصیف می کنند، تبدیل شده و عددی هستند. این امر استفاده مستقیم از آنها را با شبکه های عصبی که مقادیر ورودی و خروجی عددی را انتظار دارند، آسان می کند و یک انتخاب ایده آل برای اولین شبکه عصبی ما در PyTorch است.

می توانید این مجموعه داده را از اینجا دانلود کنید.

مجموعه داده را دانلود کنید و آن را در پوشه ، همان مکانی که فایل پایتون خود قرار دادید، بگذارید. آن را با نام فایل pima-indians-diabetes.csv ذخیره کنید. نگاهی به داخل فایل بیندازید؛ شما باید ردیف هایی از داده ها را مانند زیر ببینید:

6,148,72,35,0,33.6,0.627,50,1
1,85,66,29,0,26.6,0.351,31,0
8,183,64,0,0,23.3,0.672,32,1
1,89,66,23,94,28.1,0.167,21,0
0,137,40,35,168,43.1,2.288,33,1
...

اکنون می توانید فایل را به عنوان ماتریس اعداد با استفاده از تابع ()loadtxt در Numpy بارگذاری کنید. هشت متغیر ورودی و یک متغیر خروجی (ستون آخر) وجود دارد. شما در حال یادگیری مدلی برای نگاشت ردیف های متغیرهای ورودی X به یک متغیر خروجی y خواهید بود, که به صورت رو به رو خلاصه می شود : y=f(X)

متتغیرهای ورودی X:
  • تعداد دفعات بارداری
  • غلظت گلوکز پلاسما در 2 ساعت در آزمایش تحمل گلوکز خوراکی
  • فشار خون دیاستولیک (میلی متر جیوه)
  • ضخامت چین های پوستی سه سر بازو (میلی متر)
  • انسولین سرم 2 ساعته (μIU/ml)
  • شاخص توده بدنی (وزن بر حسب کیلوگرم / (قد بر حسب متر) 2)
  • عملکرد شجره نامه دیابت
  • سن (سال)
متغیر خروجی y :
  • برچسب کلاس (0 یا 1 )

هنگامی که فایل CSV در حافظه بارگذاری شد، می توانید ستون های داده را به متغیرهای ورودی و خروجی تقسیم کنید.

داده ها در یک آرایه دوبعدی ذخیره می شوند که در آن بعد اول ردیف ها و بعد دوم ستون ها هستند، به عنوان مثال (ردیف ها، ستون ها). می‌توانید با انتخاب زیرمجموعه‌های ستون‌ها با استفاده از عملگر استاندارد برش NumPy یعنی «:» آرایه را به دو آرایه تقسیم کنید. می توانید هشت ستون اول را از نمایه 0 تا نمایه 7 از طریق برش 0:8 انتخاب کنید. سپس می توانید ستون خروجی (متغیر نهم) را از طریق شاخص 8 انتخاب کنید.

# load the dataset, split into input (X) and output (y) variables
dataset = np.loadtxt('pima-indians-diabetes.csv', delimiter=',')
X = dataset[:,0:8]
y = dataset[:,8]

اما این داده ها باید ابتدا به تانسورهای PyTorch تبدیل شوند. یک دلیل این است که PyTorch معمولاً در یک ممیز شناور(اعداد اعشار) 32 بیتی کار می کند در حالی که NumPy به طور پیش فرض از یک ممیز شناور 64 بیتی استفاده می کند. تبدیل به تانسورهای PyTorch می‌تواند از تبدیل ضمنی که ممکن است مشکلاتی ایجاد کند جلوگیری کند. همچنین می‌توانید از این فرصت استفاده کنید و شکل را مطابق با آنچه PyTorch انتظار دارد، اصلاح کنید، به عنوان مثال ماتریس n *1 را به nبردار ترجیح دهید.

برای ایجاد، یک تانسور از آرایه های NumPy :

X = torch.tensor(X, dtype=torch.float32)
y = torch.tensor(y, dtype=torch.float32).reshape(-1, 1)

اکنون آماده تعریف مدل شبکه عصبی خود هستید.

تعریف مدل

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

مدل را می توان به عنوان دنباله ای از لایه ها تعریف کرد. شما یک مدل Sequential با لایه های لیست شده ایجاد می کنید. اولین کاری که باید انجام دهید این است که مطمئن شوید لایه اول دارای تعداد صحیح ویژگی های ورودی است. در این مثال می توانید بعد ورودی 8 را برای هشت متغیر ورودی به صورت یک بردار مشخص کنید.

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

لایه های کاملا متصل یا لایه های متراکم با استفاده از کلاس Linear در PyTorch تعریف می شوند. این به سادگی به معنای عملیاتی شبیه ضرب ماتریس است. می توانید تعداد ورودی ها را به عنوان آرگومان اول و تعداد خروجی ها را به عنوان آرگومان دوم مشخص کنید. تعداد خروجی ها را گاهی تعداد نورون ها یا تعداد گره های لایه می نامند.

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

در این مثال، از تابع فعال‌سازی واحد خطی اصلاح‌شده، به نام ReLU، در دو لایه اول و تابع سیگموئید در لایه خروجی استفاده خواهید کرد.

یک سیگموئید در لایه خروجی تضمین می کند که خروجی بین 0 و 1 است، که به راحتی می توان با احتمال کلاس 1 نگاشت یا به طبقه بندی سخت هر یک از کلاس ها با آستانه برش 0.5 نگاشت کرد. در گذشته، ممکن است از توابع فعال‌سازی سیگموئید و tanh برای همه لایه‌ها استفاده می‌کردید، اما مشخص شد که فعال‌سازی سیگموئید می‌تواند منجر به مشکل ناپدید شدن گرادیان در شبکه‌های عصبی عمیق شود و فعال‌سازی ReLU عملکرد بهتری را از هر دو نظر سرعت و دقت ارائه می‌دهد.

با اضافه کردن هر لایه می توانید همه آن را با هم ترکیب کنید تا:

مدل مورد نظر ردیف هایی از داده با 8 متغیر را دارد (آرگومان اول در لایه اول روی 8 تنظیم شده است)
اولین لایه پنهان دارای 12 نورون است و به دنبال آن یک تابع فعال سازی ReLU وجود دارد
لایه پنهان دوم دارای 8 نورون است و به دنبال آن یک تابع فعال سازی ReLU دیگر وجود دارد
لایه خروجی دارای یک نورون است و به دنبال آن یک تابع فعال سازی سیگموئید قرار دارد

...

model = nn.Sequential(
    nn.Linear(8, 12),
    nn.ReLU(),
    nn.Linear(12, 8),
    nn.ReLU(),
    nn.Linear(8, 1),
    nn.Sigmoid()

شما می توانید مدل را با چاپ کردن آن به صورت زیر بررسی کنید:

print(model)

شما خواهید دید :

Sequential(
  (0): Linear(in_features=8, out_features=12, bias=True)
  (1): ReLU()
  (2): Linear(in_features=12, out_features=8, bias=True)
  (3): ReLU()
  (4): Linear(in_features=8, out_features=1, bias=True)
  (5): Sigmoid()
)

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

اما توجه داشته باشید که در PyTorch، راه پیچیده تری برای ایجاد یک مدل وجود دارد. مدل بالا را می توان به عنوان یک کلاس پایتون به ارث رسیده از nn.Module ایجاد کرد:

...

class PimaClassifier(nn.Module):
    def __init__(self):
        super().__init__()
        self.hidden1 = nn.Linear(8, 12)
        self.act1 = nn.ReLU()
        self.hidden2 = nn.Linear(12, 8)
        self.act2 = nn.ReLU()
        self.output = nn.Linear(8, 1)
        self.act_output = nn.Sigmoid()

    def forward(self, x):
        x = self.act1(self.hidden1(x))
        x = self.act2(self.hidden2(x))
        x = self.act_output(self.output(x))
        return x

model = PimaClassifier()
print(model)

در این حالت، مدل چاپ شده به صورت زیر خواهد بود:

PimaClassifier(
  (hidden1): Linear(in_features=8, out_features=12, bias=True)
  (act1): ReLU()
  (hidden2): Linear(in_features=12, out_features=8, bias=True)
  (act2): ReLU()
  (output): Linear(in_features=8, out_features=1, bias=True)
  (act_output): Sigmoid()
)

در این رویکرد، یک کلاس باید تمام لایه ها را در سازنده تعریف کرده باشد، زیرا شما باید تمام اجزای آن را هنگام ایجاد آماده کنید، اما ورودی هنوز ارائه نشده است. توجه داشته باشید که برای بوت استرپ کردن مدل خود باید سازنده کلاس والد (خط super().init()) را فراخوانی کنید. همچنین باید یک تابع ()forward در کلاس تعریف کنید تا بگویید، اگر یک تانسور ورودی x ارائه شده است، چگونه تانسور خروجی را در برگشت تولید می‌کنید.

از خروجی بالا می بینید که مدل به یاد می آورد که هر لایه را چگونه فراخوانی می کنید.

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

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

loss_fn = nn.BCELoss()  # binary cross entropy
optimizer = optim.Adam(model.parameters(), lr=0.001)

بهینه ساز معمولاً دارای برخی پارامترهای پیکربندی است. مهمتر از همه، نرخ یادگیری lr. اما همه بهینه سازها باید بدانند چه چیزی را بهینه کنند. از این رو. شما به model.parameters()، که مولد تمام پارامترهای مدلی است که ایجاد کرده اید،احتیاج دارید.

آموزش یک مدل

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

آموزش یک مدل شبکه عصبی معمولاً در دوره‌ها (Epochs) و دسته‌ای(Batch) طول می‌کشد. آنها اصطلاحاتی برای نحوه ارسال داده به یک مدل هستند:

Epoch: کل مجموعه داده آموزشی را یک بار به مدل منتقل می کند
Batch: یک یا چند نمونه به مدل ارسال می شود که از الگوریتم گرادیان کاهشی برای یک تکرار اجرا می شود.

به زبان ساده، کل مجموعه داده به دسته‌هایی تقسیم می‌شود، و شما دسته‌ها را یکی یکی به یک مدل با استفاده از یک حلقه آموزشی منتقل می‌کنید. وقتی تمام دسته ها را تمام کردید، یک دوره را به پایان رسانده اید. سپس می توانید دوباره با همان مجموعه داده شروع کنید و دوره دوم را شروع کنید و به اصلاح مدل ادامه دهید. این روند تا زمانی که شما از خروجی مدل راضی باشید تکرار می شود.

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

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

ساده ترین راه برای ایجاد یک حلقه آموزشی استفاده از دو حلقه for تو در تو، یکی برای دوره ها و دیگری برای دسته ها است:

n_epochs = 100
batch_size = 10

for epoch in range(n_epochs):
    for i in range(0, len(X), batch_size):
        Xbatch = X[i:i+batch_size]
        y_pred = model(Xbatch)
        ybatch = y[i:i+batch_size]
        loss = loss_fn(y_pred, ybatch)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
    print(f'Finished epoch {epoch}, latest loss {loss}')

وقتی این اجرا شد، موارد زیر را چاپ می کند:

Finished epoch 0, latest loss 0.6271069645881653
Finished epoch 1, latest loss 0.6056771874427795
Finished epoch 2, latest loss 0.5916517972946167
Finished epoch 3, latest loss 0.5822567939758301
Finished epoch 4, latest loss 0.5682642459869385
Finished epoch 5, latest loss 0.5640913248062134
...

ارزیابی مدل

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

شما می توانید مدل خود را در مجموعه داده های آموزشی خود به همان روشی که از مدل در آموزش فراخوانی کردید، ارزیابی کنید. این کار پیش‌بینی‌هایی را برای هر ورودی ایجاد می‌کند، اما پس از آن شما هنوز باید یک امتیاز برای ارزیابی محاسبه کنید. این امتیاز می تواند مشابه با عملکرد تابع ضرر شما یا چیزی متفاوت باشد. از آنجا که شما در حال انجام طبقه بندی باینری هستید، می توانید با تبدیل خروجی (عدد اعشاری در محدوده 0 تا 1) به عدد صحیح (0 یا 1) و مقایسه با برچسبی که می شناسیم، از دقت به عنوان امتیاز ارزیابی خود استفاده کنید.

این کار به صورت زیر انجام می شود:

# compute accuracy (no_grad is optional)
with torch.no_grad():
    y_pred = model(X)

accuracy = (y_pred.round() == y).float().mean()
print(f"Accuracy {accuracy}")

تابع round () عدد اعشار را به نزدیکترین عدد صحیح گرد می کند. عملگر == یک تانسور بولی را مقایسه و برمی گرداند که می تواند به اعداد ممیز شناور 1.0 و 0.0 تبدیل شود. تابع mean() تعداد 1ها را به شما ارائه می دهد (یعنی پیش بینی مطابق با برچسب) تقسیم بر تعداد کل نمونه ها. no_grad () اختیاری است اما پیشنهاد می‌شود، بنابراین شما y_pred را از به خاطر سپردن نحوه بدست آوردن عدد راحت می‌کنید، زیرا نمی‌خواهید روی آن تمایز ایجاد کنید.

با کنار هم قرار دادن همه چیز، کد زیر کامل است.

import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim

# load the dataset, split into input (X) and output (y) variables
dataset = np.loadtxt('pima-indians-diabetes.csv', delimiter=',')
X = dataset[:,0:8]
y = dataset[:,8]

X = torch.tensor(X, dtype=torch.float32)
y = torch.tensor(y, dtype=torch.float32).reshape(-1, 1)

# define the model
model = nn.Sequential(
    nn.Linear(8, 12),
    nn.ReLU(),
    nn.Linear(12, 8),
    nn.ReLU(),
    nn.Linear(8, 1),
    nn.Sigmoid()
)
print(model)

# train the model
loss_fn   = nn.BCELoss()  # binary cross entropy
optimizer = optim.Adam(model.parameters(), lr=0.001)

n_epochs = 100
batch_size = 10

for epoch in range(n_epochs):
    for i in range(0, len(X), batch_size):
        Xbatch = X[i:i+batch_size]
        y_pred = model(Xbatch)
        ybatch = y[i:i+batch_size]
        loss = loss_fn(y_pred, ybatch)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
    print(f'Finished epoch {epoch}, latest loss {loss}')

# compute accuracy (no_grad is optional)
with torch.no_grad():
    y_pred = model(X)
accuracy = (y_pred.round() == y).float().mean()
print(f"Accuracy {accuracy}")

می‌توانید تمام کدها را در فایل پایتون کپی کنید و آن را به‌عنوان «pytorch_network.py» در همان فهرستی که فایل داده‌تان «pima-indians-diabetes.csv» است ذخیره کنید. سپس می توانید فایل پایتون را به عنوان یک اسکریپت از خط فرمان خود اجرا کنید.

با اجرای این مثال، باید ببینید که حلقه آموزشی در هر دوره با از تابع ضرر با دقت نهایی چاپ شده در آخر پیشرفت می کند. در حالت ایده آل، شما دوست دارید که مقدار ضرر به صفر برسد و دقت به 1.0 (مثلاً 100٪) برسد. این برای هیچ مسئله ای جز پیش پا افتاده ترین مسائل (مسائل ساده ) یادگیری ماشین ممکن نیست. در عوض، شما همیشه در مدل خود خطا خواهید داشت. هدف انتخاب یک پیکربندی مدل و پیکربندی آموزشی است که کمترین ضرر و بالاترین دقت ممکن را برای یک مجموعه داده معین به دست آورد.

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

Accuracy: 0.7604166865348816
Accuracy: 0.7838541865348816
Accuracy: 0.7669270634651184
Accuracy: 0.7721354365348816
Accuracy: 0.7669270634651184

می توانید ببینید که تمام امتیازات دقت حدود 77٪ است.

پیش بینی کنید

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

...

# make probability predictions with the model
predictions = model(X)
# round predictions
rounded = predictions.round()

متناوباً، می‌توانید برای پیش‌بینی مستقیم کلاس‌های احتمال را به 0 یا 1 تبدیل کنید. مثلا:

...
# make class predictions with the model
predictions = (model(X) > 0.5).int()

مثال کامل زیر پیش‌بینی‌هایی را برای هر نمونه در مجموعه داده انجام می‌دهد، سپس داده‌های ورودی، کلاس پیش‌بینی‌شده و کلاس مورد انتظار را برای پنج مثال اول در مجموعه داده چاپ می‌کند.

import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim

# load the dataset, split into input (X) and output (y) variables
dataset = np.loadtxt('pima-indians-diabetes.csv', delimiter=',')
X = dataset[:,0:8]
y = dataset[:,8]

X = torch.tensor(X, dtype=torch.float32)
y = torch.tensor(y, dtype=torch.float32).reshape(-1, 1)

# define the model
class PimaClassifier(nn.Module):
    def __init__(self):
        super().__init__()
        self.hidden1 = nn.Linear(8, 12)
        self.act1 = nn.ReLU()
        self.hidden2 = nn.Linear(12, 8)
        self.act2 = nn.ReLU()
        self.output = nn.Linear(8, 1)
        self.act_output = nn.Sigmoid()

    def forward(self, x):
        x = self.act1(self.hidden1(x))
        x = self.act2(self.hidden2(x))
        x = self.act_output(self.output(x))
        return x

model = PimaClassifier()
print(model)

# train the model
loss_fn   = nn.BCELoss()  # binary cross entropy
optimizer = optim.Adam(model.parameters(), lr=0.001)

n_epochs = 100
batch_size = 10

for epoch in range(n_epochs):
    for i in range(0, len(X), batch_size):
        Xbatch = X[i:i+batch_size]
        y_pred = model(Xbatch)
        ybatch = y[i:i+batch_size]
        loss = loss_fn(y_pred, ybatch)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

# compute accuracy
y_pred = model(X)
accuracy = (y_pred.round() == y).float().mean()
print(f"Accuracy {accuracy}")

# make class predictions with the model
predictions = (model(X) > 0.5).int()
for i in range(5):
    print('%s => %d (expected %d)' % (X[i].tolist(), predictions[i], y[i]))

این کد از روش متفاوتی برای ساخت مدل استفاده می کند، اما از نظر عملکردی باید مانند قبل باشد. پس از آموزش مدل، پیش‌بینی‌هایی برای همه نمونه‌های مجموعه داده انجام می‌شود و ردیف‌های ورودی و مقدار کلاس پیش‌بینی‌شده برای پنج مثال اول چاپ شده و با مقدار کلاس مورد انتظار مقایسه می‌شوند. می بینید که بیشتر ردیف ها به درستی پیش بینی شده اند. در واقع، شما می توانید انتظار داشته باشید که حدود 77 درصد از ردیف ها بر اساس عملکرد تخمین زده شده شما از مدل در بخش قبل، به درستی پیش بینی شوند.

[6.0, 148.0, 72.0, 35.0, 0.0, 33.599998474121094, 0.6269999742507935, 50.0] => 1 (expected 1)
[1.0, 85.0, 66.0, 29.0, 0.0, 26.600000381469727, 0.35100001096725464, 31.0] => 0 (expected 0)
[8.0, 183.0, 64.0, 0.0, 0.0, 23.299999237060547, 0.671999990940094, 32.0] => 1 (expected 1)
[1.0, 89.0, 66.0, 23.0, 94.0, 28.100000381469727, 0.16699999570846558, 21.0] => 0 (expected 0)
[0.0, 137.0, 40.0, 35.0, 168.0, 43.099998474121094, 2.2880001068115234, 33.0] => 1 (expected 1)

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *