معرفی بهینه سازی
اکنون که شبکه عصبی ساخته شده است، می تواند داده ها را از آن عبور دهد و قادر به محاسبه ضرر باشد، گام بعدی تعیین نحوه تنظیم وزن ها و بایاس ها برای کاهش تلفات است. یافتن روشی هوشمندانه برای تنظیم وزن و سوگیری ورودی نورون ها برای به حداقل رساندن ضرر، مشکل اصلی شبکه های عصبی است.
اولین گزینه ای که ممکن است به آن فکر کنید این است که به طور تصادفی وزن ها را تغییر دهید، ضرر را بررسی کنید و این کار را تکرار کنید تا زمانی که با کمترین ضرر یافت شده خوشحال شوید. برای دیدن این در عمل، ما از یک مجموعه داده ساده تر از آنچه تاکنون با آن کار کرده ایم استفاده خواهیم کرد:
import matplotlib.pyplot as plt
import nnfs
from nnfs.datasets import vertical_data
nnfs.init()
X, y = vertical_data(samples=100, classes=3)
plt.scatter(X[:, 0], X[:, 1], c=y, s=40, cmap=’brg’)
plt.show()
که به نظر می رسد:
شکل 6.01: “داده های عمودی” نمودار شده است.
با استفاده از کد ایجاد شده قبلی تا این مرحله، می توانیم از این مجموعه داده جدید با یک شبکه عصبی ساده استفاده کنیم:
# Create dataset
X, y = vertical_data(samples=100, classes=3)
# Create model
dense1 = Layer_Dense(2, 3) # first dense layer, 2 inputs
activation1 = Activation_ReLU()
dense2 = Layer_Dense(3, 3) # second dense layer, 3 inputs, 3 outputs
activation2 = Activation_Softmax()
# Create loss function
loss_function = Loss_CategoricalCrossentropy()
سپس چند متغیر برای ردیابی بهترین ضرر و وزن ها و سوگیری های مرتبط ایجاد کنید:
# Helper variables
lowest_loss = 9999999 # some initial value
best_dense1_weights = dense1.weights.copy()
best_dense1_biases = dense1.biases.copy()
best_dense2_weights = dense2.weights.copy()
best_dense2_biases = dense2.biases.copy()
ما ضرر را به مقدار زیادی مقداردهی اولیه کردیم و زمانی که ضرر جدید و پایین تر یافت شود، آن را کاهش خواهیم داد. ما همچنین وزن ها و تعصبات را کپی می کنیم ( copy()به جای ارجاع به شیء، یک کپی کامل را تضمین می کند). اکنون هر چند بار که می خواهیم تکرار می کنیم، مقادیر تصادفی را برای وزن ها و تعصبات انتخاب می کنیم و وزن ها و سوگیری ها را در صورت ایجاد کمترین ضرر ذخیره می کنیم:
for iteration in range(10000):
# مجموعه جدیدی از وزن ها را برای تکرار ایجاد کنید
dense1.weights = 0.05 * np.random.randn(2, 3)
dense1.biases = 0.05 * np.random.randn(1, 3)
dense2.weights = 0.05 * np.random.randn(3, 3)
dense2.biases = 0.05 * np.random.randn(1, 3)
# یک پاس رو به جلو از داده های آموزشی را از طریق این لایه انجام دهید
dense1.forward(X)
activation1.forward(dense1.output)
dense2.forward(activation1.output)
activation2.forward(dense2.output)
# عملکرد فعال سازی را از طریق عبور رو به جلو انجام دهید
# خروجی لایه متراکم دوم را در اینجا می گیرد و ضرر را برمی گرداند
loss = loss_function.calculate(activation2.output, y)
# محاسبه دقت از خروجی فعال سازی2 و اهداف
# مقادیر را در امتداد محور اول محاسبه کنید
predictions = np.argmax(activation2.output, axis=1)
accuracy = np.mean(predictions==y)
# اگر ضرر کمتر است – وزن ها و تعصبات را چاپ کرده و کنار بگذارید
if loss < lowest_loss:
print(‘New set of weights found, iteration:’, iteration,
‘loss:’, loss, ‘acc:’, accuracy)
best_dense1_weights = dense1.weights.copy()
best_dense1_biases = dense1.biases.copy()
best_dense2_weights = dense2.weights.copy()
best_dense2_biases = dense2.biases.copy()
lowest_loss = loss
>>>
New set of weights found, iteration: 0 loss: 1.0986564 acc: 0.3333333333333333
New set of weights found, iteration: 3 loss: 1.098138 acc: 0.3333333333333333
New set of weights found, iteration: 117 loss: 1.0980115 acc: 0.3333333333333333
New set of weights found, iteration: 124 loss: 1.0977516 acc: 0.6
New set of weights found, iteration: 165 loss: 1.097571 acc: 0.3333333333333333
New set of weights found, iteration: 552 loss: 1.0974693 acc: 0.34
New set of weights found, iteration: 778 loss: 1.0968257 acc: 0.3333333333333333
New set of weights found, iteration: 4307 loss: 1.0965533 acc: 0.3333333333333333
New set of weights found, iteration: 4615 loss: 1.0964499 acc: 0.3333333333333333
New set of weights found, iteration: 9450 loss: 1.0964295 acc: 0.3333333333333333
ضرر مطمئنا کاهش می یابد، اگرچه نه چندان. دقت بهبود نیافت، به جز یک وضعیت منحصر به فرد که در آن مدل به طور تصادفی مجموعه ای از وزن ها را با دقت بهتر پیدا کرد. با این حال، با ضرر نسبتا بزرگ، این وضعیت پایدار نیست. اجرای 90,000 تکرار اضافی برای 100,000 در مجموع:
New set of weights found, iteration: 13361 loss: 1.0963014 acc: 0.3333333333333333
New set of weights found, iteration: 14001 loss: 1.0959858 acc: 0.3333333333333333
New set of weights found, iteration: 24598 loss: 1.0947444 acc: 0.3333333333333333
ضرر همچنان کاهش یافت، اما دقت تغییر نکرد. به نظر نمی رسد این روش قابل اعتمادی برای به حداقل رساندن ضرر باشد. پس از اجرای 1 میلیارد تکرار، نتیجه زیر بهترین (کمترین ضرر) بود:
New set of weights found, iteration: 229865000 loss: 1.0911305 acc: 0.3333333333333333
حتی با این مجموعه داده اولیه، می بینیم که جستجوی تصادفی برای ترکیب وزن و سوگیری بسیار طولانی تر از آن است که یک روش قابل قبول باشد. ایده دیگر ممکن است این باشد که به جای تنظیم پارامترها با مقادیر تصادفی انتخاب شده در هر تکرار، کسری از این مقادیر را روی پارامترها اعمال کنید. با این کار، وزن ها از آنچه در حال حاضر کمترین ضرر را برای ما به همراه دارد به جای تصادفی بی هدف، به روز می شوند. اگر تنظیم ضرر را کاهش دهد، آن را به نقطه جدیدی برای تنظیم تبدیل می کنیم. اگر در عوض ضرر به دلیل تعدیل افزایش یابد، به نقطه قبلی باز می گردیم. با استفاده از کدهای مشابه قبلی، ابتدا از انتخاب تصادفی وزن ها و سوگیری ها به تنظیم تصادفی آنها تغییر می دهیم :
# وزن ها را با چند مقدار تصادفی کوچک به روز کنید
dense1.weights += 0.05 * np.random.randn(2, 3)
dense1.biases += 0.05 * np.random.randn(1, 3)
dense2.weights += 0.05 * np.random.randn(3, 3)
dense2.biases += 0.05 * np.random.randn(1, 3)
سپس پایانه خود را تغییر می دهیم اگر عبارت به صورت زیر است:
# اگر ضرر کمتر است – وزن ها و تعصبات را چاپ کرده و کنار بگذارید
if loss < lowest_loss:
print(‘New set of weights found, iteration:’, iteration,
‘loss:’, loss, ‘acc:’, accuracy)
best_dense1_weights = dense1.weights.copy()
best_dense1_biases = dense1.biases.copy()
best_dense2_weights = dense2.weights.copy()
best_dense2_biases = dense2.biases.copy()
lowest_loss = loss
# وزن ها و سوگیری ها را برگردانید
else:
dense1.weights = best_dense1_weights.copy()
dense1.biases = best_dense1_biases.copy()
dense2.weights = best_dense2_weights.copy()
dense2.biases = best_dense2_biases.copy()
کد کامل تا این مرحله:
# مجموعه داده ایجاد کنید
X, y = vertical_data(samples=100, classes=3)
# ایجاد مدل
dense1 = Layer_Dense(2, 3) # اولین لایه متراکم، 2 ورودی
activation1 = Activation_ReLU()
dense2 = Layer_Dense(3, 3) # لایه متراکم دوم، 3 ورودی، 3 خروجی
activation2 = Activation_Softmax()
# ایجاد عملکرد از دست دادن
loss_function = Loss_CategoricalCrossentropy()
# متغیرهای کمکی
lowest_loss = 9999999 # مقداری ارزش اولیه
best_dense1_weights = dense1.weights.copy()
best_dense1_biases = dense1.biases.copy()
best_dense2_weights = dense2.weights.copy()
best_dense2_biases = dense2.biases.copy()
for iteration in range(10000):
# وزن ها را با چند مقدار تصادفی کوچک به روز کنید
dense1.weights += 0.05 * np.random.randn(2, 3)
dense1.biases += 0.05 * np.random.randn(1, 3)
dense2.weights += 0.05 * np.random.randn(3, 3)
dense2.biases += 0.05 * np.random.randn(1, 3)
# یک پاس رو به جلو از داده های آموزشی خود را از طریق این لایه انجام دهید
dense1.forward(X)
activation1.forward(dense1.output)
dense2.forward(activation1.output)
activation2.forward(dense2.output)
# عملکرد فعال سازی را از طریق عبور رو به جلو انجام دهید
# خروجی لایه متراکم دوم را در اینجا می گیرد و ضرر را برمی گرداند
loss = loss_function.calculate(activation2.output, y)
# محاسبه دقت از خروجی فعال سازی2 و اهداف
# مقادیر را در امتداد محور اول محاسبه کنید
predictions = np.argmax(activation2.output, axis=1)
accuracy = np.mean(predictions==y)
# اگر ضرر کمتر است – وزن ها و تعصبات را چاپ کرده و کنار بگذارید
if loss < lowest_loss:
print(‘New set of weights found, iteration:’, iteration,
‘loss:’, loss, ‘acc:’, accuracy)
best_dense1_weights = dense1.weights.copy()
best_dense1_biases = dense1.biases.copy()
best_dense2_weights = dense2.weights.copy()
best_dense2_biases = dense2.biases.copy()
lowest_loss = loss
# وزن ها و سوگیری ها را برگردانید
else:
dense1.weights = best_dense1_weights.copy()
dense1.biases = best_dense1_biases.copy()
dense2.weights = best_dense2_weights.copy()
dense2.biases = best_dense2_biases.copy()
>>>
New set of weights found, iteration: 0 loss: 1.0987684 acc: 0.3333333333333333 …
New set of weights found, iteration: 29 loss: 1.0725244 acc: 0.5266666666666666
New set of weights found, iteration: 30 loss: 1.0724432 acc: 0.3466666666666667 …
New set of weights found, iteration: 48 loss: 1.0303522 acc: 0.6666666666666666
New set of weights found, iteration: 49 loss: 1.0292586 acc: 0.6666666666666666 …
New set of weights found, iteration: 97 loss: 0.9277446 acc: 0.7333333333333333 …
New set of weights found, iteration: 152 loss: 0.73390484 acc: 0.8433333333333334
New set of weights found, iteration: 156 loss: 0.7235515 acc: 0.87
New set of weights found, iteration: 160 loss: 0.7049076 acc: 0.9066666666666666 …
New set of weights found, iteration: 7446 loss: 0.17280102 acc:
0.9333333333333333
New set of weights found, iteration: 9397 loss: 0.17279711 acc: 0.93
این بار ضرر به میزان مناسبی کاهش یافت و دقت به میزان قابل توجهی افزایش یافت. استفاده از کسری از مقادیر تصادفی در واقع منجر به نتیجه ای می شود که تقریبا می توانیم آن را راه حل بنامیم. اگر 100000 تکرار را امتحان کنید، پیشرفت بیشتری نخواهید کرد:
>>> …
New set of weights found, iteration: 14206 loss: 0.1727932 acc:
0.9333333333333333
New set of weights found, iteration: 63704 loss: 0.17278232 acc:
0.9333333333333333
بیایید به جای آن این را با مجموعه داده مارپیچی که قبلا دیده شده بود امتحان کنیم:
# مجموعه داده ایجاد کنید
X, y = spiral_data(samples=100, classes=3)
>>>
New set of weights found, iteration: 0 loss: 1.1008677 acc: 0.3333333333333333 …
New set of weights found, iteration: 31 loss: 1.0982264 acc: 0.37333333333333335 …
New set of weights found, iteration: 65 loss: 1.0954362 acc:
0.38333333333333336
New set of weights found, iteration: 67 loss: 1.093989 acc: 0.4166666666666667 …
New set of weights found, iteration: 129 loss: 1.0874122 acc: 0.42333333333333334 …
New set of weights found, iteration: 5415 loss: 1.0790575 acc: 0.39
این جلسه آموزشی تقریبا بدون هیچ پیشرفتی به پایان رسید. تلفات کمی کاهش یافت و دقت به سختی بالاتر از مقدار اولیه است. بعدا خواهیم فهمید که محتمل ترین دلیل این امر حداقل ضرر محلی نامیده می شود. پیچیدگی داده ها نیز در اینجا بی ربط نیست. به نظر می رسد که مشکلات سخت به دلایلی سخت هستند و ما باید هوشمندانه تر به این مشکل نزدیک شویم.
مواد تکمیلی: https://nnfs.io/ch6
کد فصل، منابع بیشتر و اشتباهات این فصل.