ساخت یک شبکه عصبی ساده – قسمت دوم : پیاده سازی

در ادامه بخش گذشته که بحث ایجاد مسئله ای ساده را بیان کردیم، بگزارید بگوییم دستگاهی با ۴ دکمه وجود دارد که اگر شما دکمه درست را بفشارید به شما غذا می دهد ( یا اگر ربات باشید احتمالا انرژی می دهد )، هدف مدنظر، یادگیری این موضوع است که کدام دکمه غذاها را مهیا می کند.

مقاله مرتبط :

 

می توانیم زمان فشرده شده یک کلید را (ا ز نظر گرافیکی ) به صورت زیر نشان دهیم:

بخش بندی و جزء به جزء کردن کلیت این مسئله کاری آسان است، بنابراین بیایید تمام خروجی های ممکن از جمله جواب مسئله را مشاهده کنیم:

دکمه ۳ را برای دریافت مرغ بفشارید

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

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

باتوجه به اینکه همه وزن ها صفر است، شبکه عصبی در حالتی بی نتیجه قرار دارد هرچند کاملاً متصل و مانند حالت اولیه اش است

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

بگزارید با ورودی ها و وزن ها آغاز کنیم ( من از Javascript استفاده خواهم کرد ):

var inputs = [0,1,0,0];
var weights = [0,0,0,0];


// we can call these vectors for convenience.

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

function evaluateNeuralNetwork(inputVector, weightVector){    
  var result = 0; 
  inputVector.forEach(function(inputValue, weightIndex) {
   layerValue = inputValue*weightVector[weightIndex];
    result += layerValue;
  });  
  return (result.toFixed(2)); 
}
// Might look complex, but all it does is multiply weight/input pairs and adds the result.

و همانطور که انتظار می رود اگر کد بالا را اجرا کنیم، باید خروجی مشابه با گراف و مدل مدنظرمان را حاصل کند…

evaluateNeuralNetwork(inputs, weights); // 0.00

مثال زنده (اجرای آنلاین کد)

گام بعدی یا درواقع ارتقای شبکه عصبیمان، راهی برای بررسی خروجی یا نتیجه شبکه در مقابل موقعیت واقعی مدنظر می باشد، بیایید در ابتدا این واقعیت خاص را به حالت مقدار متغیر رمزنگاری کنیم:

به منظور شناسایی خطا ( و میزان آن ) یک تابع خطا به شبکه اضافه می کنیم:

Error = Reality – Neural Net Output

حال با این دو مؤلفه جدید، می توانیم شبکه عصبیمان را ارزیابی کنیم:

و از آن مهم تر، وقتی واقعیت نتیجه ای مثبت ایجاد کند چطور؟ ( شام مرغ در مثال ما )

خب حالا قطعاً می دانیم که مدل شبکه عصبیمان کار نمی کند ( و به میزان نامشخص )، بسیار عالی! این عالی است چراکه هم اکنون می توانیم از این خطا برای بهبود یادگیریمان استفاده کنیم، این موارد مطرح شده وقتی بیشتر معنا پیدا می کند که تابع خطایمان را مجدداً و به صورت زیر تعریف کنیم:

Error = Desired Output – Neural Net Output

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

دست کاری های بعدی انجام شده در نمونه کدمان فقط بحث اضافه کردن متغیری جدید می باشد:

var input = [0,0,1,0];
var weights = [0,0,0,0];
var desiredResult = 1;

و یک تابع جدید:

function evaluateNeuralNetError(desired,actual) {
  return (desired — actual);
}
// After evaluating both the Network and the Error we would get:
// "Neural Net output: 0.00 Error: 1"

مثال زنده (اجرای آنلاین کد)

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

خب یک مرحله آموزش برای شبکه عصبی چطور است؟

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

یک الگوریتم یادگیری در طبیعت می تواند به عنوان تغییری در وضعیت فیزیکی و شیمیایی خصوصیت های عصب ها پس از انجام آزمایش باشد:

به نمایش درآوردن تغییرپذیری ۲ عصب در طول زمان

در قالب کد و مدلمان، یک الگوریتم یادگیری به این معنی است که ما به منظور ساده سازی زندگی مان، چیزی را در طول زمان تغییر خواهیم داد، بیایید یک متغیر را برای نشان دادن میزان مدنظر، اضافه کنیم:

var learningRate = 0.20; 
// bigger rate,bigger faster learnings : )

چه چیزی را تغییر خواهیم داد؟

وزن ها را تغییر می دهیم ( مشابه مدل خرگوش ( بخش اول مقاله ) که تغییر داده شد !)، به طور خاص، وزن های خروجی هایی که مدنظرمان می باشد:

چگونگی کد الگوریتم یادگیری مدنظر، صرفاً مسئله انتخاب کردن است، من برای سادگی موضوع، فقط نرخ یادگیری را به وزن ها اضافه کردم، و این تابع حاصل شد:

function learn(inputVector, weightVector) {
weightVector.forEach(function(weight, index, weights) {
if (inputVector[index] > 0) {

weights[index] = weight + learningRate;
}
});
}

در استفاده از این تابع یادگیری، مقدار نرخ یادگیریمان به بردار وزن عصب های فعال اضافه می شود، قبل و بعد از یک مرحله یادگیری ( یا آزمایش ) نتیجه به صورت زیر خواهد بود:

// Original weight vector: [0,0,0,0]
// Neural Net output: 0.00 Error: 1
learn(input, weights);// New Weight vector: [0,0.20,0,0]
// Neural Net output: 0.20 Error: 0.8
// If it is not apparently obvious, a Neural Net output closer to 1
// (chicken dinner) is what we want, so we are heading in the right
// direction

مثال زنده (اجرای آنلاین کد)

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

بحث زیادی در این زمینه وجود ندارد و صرفاً در طبیعت کارهای زیادی را بارها و بارها انجام می دهیم، در قالب کد فقط یک عددی به عنوان تعداد آزمایش ها(تکرارها) مشخص می کنیم؛

var trials = 6;

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

function train(trials) {
for (i = 0; i < trials; i++) {
neuralNetResult = evaluateNeuralNetwork(input, weights);
learn(input, weights);
}
}

و حاصل کارمان:

Neural Net output: 0.00 Error: 1.00 Weight Vector: [0,0,0,0]
 
Neural Net output: 0.20 Error: 0.80 Weight Vector: [0,0,0.2,0]
 
Neural Net output: 0.40 Error: 0.60 Weight Vector: [0,0,0.4,0]
 
Neural Net output: 0.60 Error: 0.40 Weight Vector: [0,0,0.6,0]
 
Neural Net output: 0.80 Error: 0.20 Weight Vector: [0,0,0.8,0]
 
Neural Net output: 1.00 Error: 0.00 Weight Vector: [0,0,1,0]
// Chicken Dinner !

مثال زنده (اجرای آنلاین کد)

حال یک بردار وزن داریم که اگر بردار ورودی مشابه وضعیت واقعی باشد ( فشرده شدن دکمه  ۳)، تنها در خروجی ۱ ( شام مرغ ) نتیجه خواهد داد.

خب مزیت این چیزی که هم اکنون ساختیم چه می باشد؟

در مدل خاص مدنظر ما، شبکه عصبی مان(پس از آموزش داده شدن) می تواند عمل شناسایی را انجام دهد یا بین ورودی ها تفکیک و تمایز ایجاد کند و بگوید که کدام یک از آنها می تواند خروجی مدنظر را حاصل کند ( البته براساس هر وضعیت خاص، به کدی متناسب با آن نیاز خواهیم داشت 🙁

سلام بچه ها، با آقای شبکه عصبی ! آشنا شوید.

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

توجه:

  • مکانیزمی برای ذخیره کردن وزن های آموزش دیده شده وجود ندارد، بنابراین این شبکه عصبی پس از هر بارگذاری مجدد یا اجرای دوباره کد، هرچیزی را که یاد گرفته است، از دست می دهد.
  • اگر شما یک انسان یا ماشین را برای فشردن دکمه ها به طور تصادفی در نظر بگیرید، این پروسه ممکن است نیاز به ۶ آزمایش موفق برای آموزش کامل این شبکه عصبی داشته باشد… این موضوع ممکن است زمانبر باشد.
  • در موارد مهم، شبکه های زیستی نرخ یادگیری برابر ۱ دارند، بنابراین پروسه صرفاً نیاز به یک مرحله آزمایش دارد.
  • یک الگوریتم یادگیری که ماهیت عصب های زیستی را همانند یکدیگر می کند ( تغییر می دهد )، با عنوان جذاب قانون widroff-hoff  یا یادگیری widroff-hoff  شناخته می شود.
  • آستانه عصب ها ( در مثال ما برابر ۱ است ) و اثرات یادگیری بیش از حد ( به همراه آزمایش های بیشتر،‌خروجی بزرگ تر از ۱ خواهد بود )، قابل کنترل می باشد، اما در طبیعت مهم است و منبعی از رفتاری پیچیده و بزرگ می باشد.
  • امتحان کردن مقدار منفی برای وزن ها

نکته ها و مطالعه بیشتر:

من از مباحث ریاضی و مقادیر پارامترهای سخت گیرانه اجتناب کردم، اما صرفاً اگر می خواهید در جریان باشید، باید بگویم که ما یک پرسپترون ( عصبی برای شناسایی الگوها ) ساختیم که به عنوان الگوریتی برای یادگیری باناظر در دسته بندهای دودویی مظرح است.

ساختار زیستی مغز، موضوع تحقیقاتی بسیار وسیعی می باشد. به دلیل در دسترس نبودن و پیچیدگی آن، همچنان اطلاعات آشکار نشده زیادی در این زمینه وجود دارد، احتمالاً بهترین موضوع برای شروع تحقیق در این زمینه، علوم اعصاب(Purves) و علوم اعصاب شناختی(Gazzaniga) می باشد.

من مثال خرگوش را از Gateway to Memory (Gluck) گرفته و دست کاری و تطبیق دادم، و آن نیز مقدمه ای فوق العاده بر گراف ها دارد.

منبع دیگری که بسیار مورد کنکاش واقع شد، An Introduction to Neural Networks (Gurney) است، و برای نیازهای عمومی تان در زمینه هوش مصنوعی، بسیار مفید است.

حال در Python ! با تشکر از Ilya Anshmidt، برای فراهم کردن نسخه python از مدلمان:

inputs = [0, 1, 0, 0]
weights = [0, 0, 0, 0]
desired_result = 1
learning_rate = 0.2
trials = 6

def evaluate_neural_network(input_array, weight_array):
      result = 0
      for i in range(len(input_array)):
            layer_value = input_array[i] * weight_array[i]
            result += layer_value
      print("evaluate_neural_network: " + str(result))
      print("weights: " + str(weights))
      return result
     
def evaluate_error(desired, actual):
      error = desired - actual
      print("evaluate_error: " + str(error))
      return error
     
def learn(input_array, weight_array):
      print("learning...")
      for i in range(len(input_array)):
            if input_array[i] > 0:
                  weight_array[i] += learning_rate
                 
def train(trials):
      for i in range(trials):
            neural_net_result = evaluate_neural_network(inputs, weights)
            learn(inputs, weights)
     
           
train(trials)

حال در GO ! با تشکر از Kieran Maher، برای فراهم کردن نسخه GO از مدلمان:

package mainimport (
 "fmt"
 "math"
)
func main() {
 fmt.Println("Creating inputs and weights ...")
inputs := []float64{0.00, 0.00, 1.00, 0.00}
 weights := []float64{0.00, 0.00, 0.00, 0.00}
 desired := 1.00
 learningRate := 0.20
 trials := 6
train(trials, inputs, weights, desired, learningRate)
}
func train(trials int, inputs []float64, weights []float64, desired float64, learningRate float64) {for i := 1; i < trials; i++ {
  weights = learn(inputs, weights, learningRate)
  output := evaluate(inputs, weights)
  errorResult := evaluateError(desired, output)
fmt.Print("Output: ")
  fmt.Print(math.Round(output*100) / 100)
  fmt.Print("\nError: ")
  fmt.Print(math.Round(errorResult*100) / 100)
  fmt.Print("\n\n")
 }
}func learn(inputVector []float64, weightVector []float64, learningRate float64) []float64 {
 for index, inputValue := range inputVector {
  if inputValue > 0.00 {
   weightVector[index] = weightVector[index] + learningRate
  }
 }
return weightVector
}
func evaluate(inputVector []float64, weightVector []float64) float64 {
 result := 0.00
for index, inputValue := range inputVector {
  layerValue := inputValue * weightVector[index]
  result = result + layerValue
 }
return result
}
func evaluateError(desired float64, actual float64) float64 {
 return desired - actual
}

بیشتر بخوانید :

منبع Becoming Human Tutorials Point MIT Press INF

همچنین ببینید

فناوری تشخیص چهره و کاربردهای آن، تاریخچه تکنولوژی تشخیص چهره

فناوری تشخیص چهره و کاربردهای آن + تاریخچه

فناوری تشخیص چهره یک فناوری بیومتریک است که با استفاده از تجزیه و تحلیل الگوهایی …

3 نظر

  1. عالی بود آموزش تون. مررسی

  2. سلام و خسته نباشید.
    بسیار مفید و واضح بود توضیحاتتون. ممنون

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

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