ایجاد یک شبکۀ عصبی در NTL+pg | IFCM ایران
IFC Markets کارگزار CFD آنلاین

ایجاد یک شبکۀ عصبی در NTL+

مقدمه

شکبۀ عصبی مصنوعی - مدل های ریاضی و کاربردهای سخت افزار یا نرم افزارشان که بر مبنای سازمان و عملکرد زیستی شبکه های عصبی ایجاد می شوند - شبکه های سلول های عصبی (نورون های) مغز.

در حال حاضر، شبکه های عصبی به شکل گسترده ای در بسیاری از وظایف تشخیص، رده بندی، حافظۀ پیوندی، تعیین الگوها، تخمین و غیره مورد استفاده قرار می گیرند.

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

از طرف دیگر، ما تلاش خواهیم کرد تا با استفاده از زبان NTL+ ، شبکۀ خنثای خودمان را ایجاد و قابلیت های برنامه نویسی شی ء گرایش را بسنجیم.

انتخاب یک عمل

در این مقاله به بیان این فرضیه می پردازیم که به پشتوانۀ میله های قبلی این امکان وجود دارد که نوع احتمالی (صعودی یا نزولی) میلۀ بعدی را پیش بینی کنیم.

این عمل با رده بندی ها ارتباط دارد. ما همچنین اطلاعات تاریخی گسترده ای دربارۀ ابزارهای مالی در اختیار داریم که اجازه می دهد بتوانیم از آمار تاریخی، خروجی (اکسپرت) دلخواه مان را به دست آوریم. به همین دلیل، شبکه ای بر اساس perceptron چند لایه ایجاد خواهیم کرد.

اکنون، شبکه ای ایجاد می کنیم که بر اساس بسته شدن قیمت های میله های k نوع میلۀ بعدی را پیش بینی می کند. اگر قیمت بسته شدن از قیمت بسته شدن میلۀ قبلی بالاتر باشد، خروجی دلخواه بعدی را 1 در نظر می گیریم (افزایش قیمت). در موارد دیگر، خروجی دلخواه برابر با 0 است (قیمت تغییر نمی کند یا افت می کند).

ایجاد شبکه

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

همینک یک شبکه با یک لایۀ ورودی، یک لایۀ پنهان و یک لایۀ خروجی ایجاد می کنیم. تصویر زیر در نمایی کلی ساختار شبکه مان را نشان می دهد. x1 - xn ورودی ها (قیمت های بسته شدن)، wi,j - وزن های لبه های برآمده از گرۀ i و رونده بسوی گرۀ j؛ عصب های y1 - ym مربوط به لایۀ پنهان، خروجی های شبکۀ o1 - ok .


ضمن اینکه، شیب های ورودی در شبکه وجود دارند. کاربرد این ورودی ها، این قابلیت را به شبکه مان می دهد تا تابع فعال سازی را در راستای محورx انتقال دهد بنابراین نه تنها شبکه می تواند شیب تابع فعال سازی را تغییر دهد بلکه تغییر خطی اش را نیز میسر می کند.

1. نمودار تابع فعال سازی در = 1
2. نمودار تابع فعاال سازی در =2 و = 1
3. نمودار تابع فعال سازی با انتقال در =2, = 1 و = 1

مقدار هر گره از شبکه طبق فرمول زیر محاسبه خواهد شد:
در اینجا (f(x برابر است تابع فعال سازی و n برابر است با تعداد گره ها در لایۀ قبلی.

تابع های فعال سازی

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

تابع فِرمی (منحنی نمایی):


منحنی گویا:


تانژانت هیپربولیک:


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

روند آموزش شبکه

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

هم اکنون برای انجام روند آموزش، به توالی مراحل زیر نیاز داریم:

  1. . ارائۀ مقادیر تصادفی کوچک به وزن های تمام لبه ها
  2. محاسبۀ تطابقات برای تمام خروجی های شبکه
    ، که در اینجا oj برابر است با خروجی محاسبه شدۀ شبکه، و tj برابر است با مقدار مورد انتظار (واقعی)
  3. برای هر گره به استثناء آخرین محاسبۀ یک تطابق طبق فرمول
    ، که در اینجا ωj,k برابر است با وزن ها در لبه ها که از سوی گره می آیند که برای آن تطابق محاسبه شده و برابر است با تطابق های محاسبه شده برای گره های واقع شده نزدیک تر به لایۀ خروجی.
  4. محاسبۀ تطابق برای هر لبۀ شبکه:
    در اینجا oi برابر است با خروجی محاسبه شدۀ گره که لبه از آن می آید. خطار برای این لبه محاسبه می شود و برابر است با تطابق محاسبه شده برای گره که لبۀ تعیین شده به آن می آید.
  5. مقادیر وزن صحیح برای تمام لبه ها:
  6. تکرار مراحل 2 - 5 برای تمامی مثال های آموزش یا معیار ثبت شده برای کیفیت آموزش تحقق یابد.

آماده کردن آمار ورودی

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

توصیه می شود که تمامی بردارهای ورودی عادی سازی شوند بطوریکه مؤلفه های شان در محدودۀ [0;1] یا [-1;1] قرار بگیرند. عادی سازی باعث می شود که تمامی بردارهای ورودی در روند آموزش شبکه تناسب پیدا کنند و در آخر یک روند صحیح آموزش حاصل گردد.

ما بردارهای ورودی مان را عادی می سازیم - مقادیر مؤلفه های شان را به محدودۀ [0;1] تبدیل می کنیم و برای این کار فرمول زیر را به کار می بریم:

قیمت های بسته شدن میله ها به عنوان اجزای بردار مورد استفاده قرار خواهند گرفت. آنهایی که با شاخص های [n+k;n+1] هستند به عنوان خروجی ها تغذیه خواهند شد که در آنجا k برابر است با اندازۀ بردار ورودی. ما مقدار دلخواه را بر اساس میلۀ nام تعیین خواهیم کرد. ما مقدار را اساس این منطق شکل می دهیم که: اگر قیمت بسته شدن برای میلۀ nام بالاتر از قیمت بسته شدن میلۀ n+1 باشد (افزایش قیمت)، خروجی دلخواه را در 1 ثبت خواهیم کرد، اگر قیمت افت کند یا تغییری نداشته باشد، مقدار را در 0 ثبت خواهیم کرد.

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

توالی آمار ارائه داده شده همچنین بر روند آموزش تاثیر می گذارد. اگر تمام بردارهای مرتبط با 1 و 0 بطور مساوی تغذیه شوند، روند آموزش استوارتر رخ می دهد.

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

تابع، محاسبۀ خطا با روش کوچکترین مربع ها، مانند زیر است:
,
در اینجا - برابر است با علامت خروجی شبکه و - برابر است با مقدار دلخواه علامت خروجی.

همینک به بررسی کد اسکریپت می پردازیم که بردارهای ورودی را برای شبکۀ عصبی مان آماده می کند.

همینک به بررسی ردۀ DataSet می پردازیم - مجموعۀ آمار. این رده شامل موارد زیر می شود:

  • آرایش بردارهای مقادیر ورودی - ورودی
  • مقدار خرجی شکل گرفته - خروجی
  • روش 'Normalize' - عادی سازی آمار
  • روش 'OutputDefine' - تعیین مقدار واقعی در ارتباط قیمت ها
  • روش 'AddData' - ضبط مقادیر در آرایش بردار ورودی و متغییر مقدار واقعی
  • روش 'To_file' - گردآوری آمار در آرایش مشترک برای ضبط متعاقب در فایل

class DataSet { array <double> input(inputVectorSize); double output; //Normalization void Normalize() { double min = input[0]; double max = input[0]; //Finding minimum and maximum values for(uint i=0;i<input.length();i++) { if(input[i]>max) max=input[i]; if(input[i]<min) min=input[i]; } //Normalizing data for(uint i=0;i<input.length();i++) { //If min==max, setting all values to 0 if(max-min<0.000005) { input[i] = 0; } else { input[i]=(input[i]-min)/(max-min); } } } //Calculating the output void OutputDefine() { //If the price goes up, output is set to 1. if(input[inputVectorSize-1]<output) { output=1; } //If the price goes down or does not change, output is set to 0 else { output=0; } } //Splitting the rawInput array into two parts: input array and output value void AddData(array <double> rawInput) { //If the sizes of the arays don't match, we show a message. if(rawInput.length()!=uint(inputVectorSize+1)) { System.Print("Wrong input array size"); } //Writing to the 'input' array and 'output' variable for(int i=0;i<inputVectorSize;i++) { input[i]=rawInput[i]; } output=rawInput[inputVectorSize]; } // Merging the 'input' array and 'output' variable into one array array<double> To_file() { array<double> temp(inputVectorSize+1); for(int i=0;i<inputVectorSize;i++) { temp[i]=input[i]; } temp[inputVectorSize]=output; return temp; } }

همینک به سنجش کد برنامه با استفاده از تابع Run() و اجرای ترتیب زیر از اعمال می پردازیم:

  • بارگذاری تمامی داده های تاریخی موجود در ترمینال در یک آرایۀ داخلی. بارگذاری برای نماد و چهارچوب زمانی ای اجرا می شود که نمودار فعلی برایش به نمایش درآمده است.
  • آراستن آرایۀ میله به اندازه ای معادل با n برابر بردار داخلی + مقدار خروجی
  • ایجاد آرایه های بردارهای ورودی؛ عادی سازی این بردارها؛ تعیین مقدار دلخواه 0 یا 1
  • ایجاد آرایۀ بردارهای ورودی چیده شده درجائیکه که بردارها با موفقیت بر جایگزین 0 و 1 منطبق هستند
  • ضبط بخش اصلی آرایه همراه با بردارهای ورودی چیده شده در فایل همراه با داده ها و ضبط بخش باقی ماندۀ داده ها در آرایه برای سنجش و متعاقباً ارزیابی همراه با روش کوچکترین مربع ها.
int Run() { // The array that holds close prices of all loaded bars array <double> data (Chart.Bars-1); // Writing data to the array 'data' for(int i=1; i < Chart.Bars;i++) { data[i-1]=Close[i]; } // Truncating excessive data that can't form the whole set data.resize((data.length/(inputVectorSize+1))*(inputVectorSize+1)); int num=0; // The array is for holding all input vectors array<DataSet> sets(data.length/(inputVectorSize+1)); array <double> temp(inputVectorSize+1); // The array is for holding input vectors in the correct order array <DataSet> alternation; // Forming elements in the 'sets' array: normalizing each vector and calculating output (0 or 1) for(int i=data.length-1;i>=0;i-=(inputVectorSize+1)) { for(int j=0;j<inputVectorSize+1;j++) { temp[j]=data[i-j]; } sets[num].AddData(temp); sets[num].OutputDefine(); sets[num].Normalize(); num++; } // Forming the array 'alternation', where all the sets are sorted, so that they go 1,0,1,0 etc. uint len = sets.length; for(uint i=0;i<len;i++) { for(uint j=0;j<sets.length;j++) { if(sets[j].output==0 && state==1) { alternation.insertLast(sets[j]); sets.removeAt(j); state = 0; break; } if(sets[j].output==1 && state==0) { alternation.insertLast(sets[j]); sets.removeAt(j); state = 1; break; } } } // The file for writing data for learning file f; f.Open("data.txt",fmWrite|fmText); // Calculating the number of sets with data for learning and testing data uint datasets = int(alternation.length()*0.9); uint testsets = alternation.length() - datasets; System.Print("datasets SETS = "+datasets); // Writing data for learning to the file for(uint i=0;i<datasets;i++) { for(int j=0;j<inputVectorSize+1;j++) { f.WriteDouble(alternation[i].To_file()[j]); } } f.Close(); System.Print("testsets SETS = "+testsets); // Data for testing // Writing to the file file t; t.Open("test.txt",fmWrite|fmText); for(uint i=0;i<testsets;i++) { for(int j=0;j<inputVectorSize+1;j++) { t.WriteDouble(alternation[i+datasets].To_file()[j]); } } t.Close(); return(0); }

شما همچنین باید متغییر جهانی int state = 0 را در این فایل تعریف کنید، این متغییر برای جایزگینی بردارهای ورود لازم است.

ایجاد رده های شبکه

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

  • یک نمونه از ردۀ 'layer' برای ارتصال ورود و لایه های پنهان شبکه
  • یک نمونه از ردۀ 'layer' برای اتصال لایه های پنهان و خروجی و شبکه
  • یک نمونه از ردۀ 'net' برای اتصال لایۀ شبکه مان

ایجاد ردۀ 'layer'

هم اکنون به رده ای نیاز داریم که دربرگیرندۀ مشخصات و روش های زیر باشد:

  • آرایۀ 'input' برای چیدن ورودی های شبکه
  • آرایۀ  'output' برای چیدن خروجی های شبکه
  • آرایۀ 'delta' برای چیدن تطابق ها
  • دو آرایۀ اندازه ای 'weights' برای وزن های لبه ها
  • روش 'LoadInputs' برای اختصاص داده مقادیر تعیین شده در آرایۀ ورودی به ورودی های لایه
  • روش 'LoadWeights' برای بارگذاری مقادیر وزن لایه از درایو سخت
  • روش 'SaveWeights' برای ذخیرۀ مقادیر وزن لایه در درایو سخت
  • سازنده حجم ضروری حافظه را برای آرایه های استفاده شده تخصیص می دهد
  • روش 'RandomizeWeights' - پرکردن وزن ها با مقادیر تصادفی
  • روش 'OutputCalculation' - محاسبۀ مقادیر خروجی
  • روش 'CalculatingDeltaLast' و 'CalculatingDeltaPrevious' - محاسبۀ تطبیق مقادیر
  • روش 'WeightsCorrection' - تصحیح مقادیر وزن
  • روش های دیگر (تشخیصی) برای نمایش اطلاعات بر صفحۀ نمایش:
    • PrintInputs() -  چاپ ورودی های یک لایه
    • PrintOutputs() - چاپ خروجی یک لایه (پس از محاسبۀ ورودی با استفاده از 'OutputCalculation' فراخوانده می شود)
    • PrintDelta() -  چاپ تطابق ها برای یک لایه (باید پس از محاسبۀ تطابق ها با استفاده از 'CalculatingDeltaLast' یا 'CalculatingDeltaPrevious' فراخوانده شود)
    • PrintWeights() - چاپ وزن های w از یک لایه

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

    extern int inputVectorSize = 8; // input vector extern int L1_Innersize = 8; // number of knots in the hidden layer without bias extern int L2_Innersize= 1; // number of knots in the output layer without bias extern double nu = 0.1; //learning rate in the backpropagation method class layer { // input values array<double> input; // output values array<double> output; // output array size int outputSize=0; // weights array<array <double>> weights; // amendments array<double> delta; // default constructor layer() { } // loading input values from the 'inp' array. bool LoadInputs(array <double> inp) { if(inp.length()+1 != input.length()) { System.Print("Loading is not possible. Array sizes do not match"); return false; } for(uint i=0;i<inp.length();i++) { input[i]=inp[i]; } return true; } // loading weights from a specifies file bool LoadWeights(string filename) { file f; if(!f.Open(filename,fmRead|fmText)) { return false; } for(uint i=0;i<weights.length();i++) { for(uint j=0;j<weights[0].length();j++) { weights[i][j]=f.ReadDouble(); } } f.Close(); return true; } // loading weights to a specified file bool SaveWeights(file f) { for(uint i=0;i<weights.length();i++) { for(uint j=0;j<weights[0].length();j++) { if(!f.WriteDouble(weights[i][j])) { f.Close(); return false; } } } return true; } // constructor // inp - array of values // size - size of output array layer(array<double> inp, int size) { input = inp; input.insertLast(1); // Bias outputSize = size; //weigths array array<array<double>> temp_weights(size, array<double>(inp.length()+1)); array<double> temp_output(size); output = temp_output; weights = temp_weights; array<double> delta_temp(size); delta = delta_temp; } //randomizing weights void RandomizeWeights() { for(uint i=0;i<weights.length();i++) { for(uint j=0;j<weights[0].length;j++) { weights[i][j]=(-0.5+double(Math.Rand())/32767)*0.1; } } } // printing weights void PrintWeights() { string line; for(uint i=0;i<weights.length();i++) { line = "weights"; for(uint j=0;j<weights[0].length;j++) { line += " ["+i+"]["+j+"]="+weights[i][j]; } System.Print(line); } } // printing input values void PrintInputs() { for(uint i=0;i<input.length;i++) { System.Print("inputs["+i+"]="+input[i]); } } // print output values void PrintOutputs() { for(uint i=0;i<output.length;i++) { System.Print("outputs["+i+"]="+output[i]); } } // printing delta values void PrintDelta() { for(uint i=0;i<delta.length();i++) { System.Print("delta ["+i+"]="+delta[i]); } } // output calculation void OutputCalculation() { // temporary array to store output values array<double> a(outputSize,0); for(int k=0;k<outputSize;k++) { for(uint i=0;i<input.length();i++) { a[k]+=weights[k][i]*input[i]; } a[k]=Activation(a[k]); } output = a; } //Changing weights of the last layer void CalculatingDeltaLast(array <double> realValues) { //System.Print("delta.length()="+delta.length); if(realValues.length()!=delta.length()) { System.Print("Расхождение в размерах массивов"); return; } for(uint i=0;i<realValues.length();i++) { delta[i]=-output[i]*(1-output[i])*(realValues[i] - output[i]); } } //Changing weight for any layers except for the last. void CalculatingDeltaPrevious(layer &inout LayerLast) { for(uint j=0;j<LayerLast.input.length()-1;j++) { double sum = 0; for(uint k=0;k<LayerLast.output.length();k++) { sum += LayerLast.delta[k]*LayerLast.weights[k][j]; } delta[j]=output[j]*(1-output[j])*sum; } } //Changed weights void WeightsCorrection() { for(uint i=0;i<weights.length();i++) { for(uint j=0;j<weights[0].length();j++) { weights[i][j] = weights[i][j] - nu*delta[i]*input[j]; } } } }

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

    void Normalize(array<double> &inout input) { double min = input[0]; double max = input[0]; //finding minimum and maximun for(uint i=0;i<input.length();i++) { if(input[i]>max) max=input[i]; if(input[i]<min) min=input[i]; } for(uint i=0;i<input.length();i++) { if(max-min<0.000005) { input[i] = 0.0; } else { input[i]=(input[i]-min)/(max-min); } } } // Activation function double Activation(double x) { return x/(Math.Abs(x)+1); }

    ایجاد ردۀ 'net'

    ما به رده ای نیاز داریم که لایه های مان را به یک شبکۀ واحد ملحق کند، به این ترتیب این رده باید شامل موارد زیر باشد:

    • روش 'Calculate' - مرتبط کردن لایه ها برای محاسبۀ خروجی شبکه. از این روش بعداً برای کار با شبکۀ آموزش یافته استفاده خواهد شد.
    • روش 'CalculateAndLearn' - محاسبۀ خروجی ها، خطاها و تطابق ها. ما برای محاسبۀ خروجی ها، روش قبلی را فرامی خوانیم و روش های مرتبط با هر لایه را برای خطاها و تطابق ها فراخوانده خواهد خواند.
    • روش 'SaveNetwork' - ذخیرۀ ضرایب (وزن ها) شبکه
    • روش 'LoadNetwork' - بارگذاری ضرایب (وزن ها) شبکه
    class net { array <double> x(inputVectorSize); array <double> y(L1_Innersize); layer L1(x,L1_Innersize); array<double> L1_outputs(L1_Innersize); layer L2(y,L2_Innersize); //Calculating output using current weights array<double> Calculate(array <double> data, bool randomWeights) { if(data.length()!=x.length()) { System.Print("Array sizes do not match"); } x = data; Normalize(x); L1.LoadInputs(x); if(randomWeights) { L1.RandomizeWeights(); L2.RandomizeWeights(); } L1.OutputCalculation(); L2.LoadInputs(L1.output); L2.OutputCalculation(); return L2.output; } //Calculating output and changing weights void CalculateAndLearn(array <double> data, array <double> realValues, bool randomWeights) { Calculate(data, randomWeights); L2.CalculatingDeltaLast(realValues); L1.CalculatingDeltaPrevious(L2); L2.WeightsCorrection(); L1.WeightsCorrection(); } //Saving the weights of the whole network bool SaveNetwork(string filename) { file f; if(!f.Open(filename,fmWrite|fmRead|fmText)) { f.Open(filename,fmWrite|fmText); } L1.SaveWeights(f); L2.SaveWeights(f); f.Close(); return true; } //Loading all weights bool LoadNetwork(string filename) { file fn; if(fn.Open(filename,fmRead|fmText)==false) { return false; } for(uint i=0;i<L1.weights.length();i++) { for(uint j=0;j<L1.weights[0].length();j++) { L1.weights[i][j]=fn.ReadDouble(); } } for(uint i=0;i<L2.weights.length();i++) { for(uint j=0;j<L2.weights[0].length();j++) { L2.weights[i][j]=fn.ReadDouble(); } } return true; } }

    بررسی کار شبکه

    در این بخش، در یک مثال ابتدایی که برای تعیین صحت رده بندی بردارهای ورودی استفاده خواهد شد، کار شبکه مان را بررسی خواهیم کرد. برای این منظور از یک شبکه با دو ورودی، دو گره در لایۀ پنهان و یک خروجی استفاده می کنیم. پارامترnu را به 1 ثبت می کنیم. دادۀ ورودی به عنوان مجموعه های جایگزین ارائه داده خواهد شد که شامل موارد زیر می شود:
    ورودی 1،2 و مقدار مورد انتظار 1
    ورود 2،1 و مقدار مورد انتظار 0
    آنها در فایلی به این شکل مشخص می شوند:

    1.00000000 2.00000000 1.00000000 2.00000000 1.00000000 0.00000000

    شما با تغذیۀ ورودی تعداد متفاوتی از مثال های آموزشی، می توانید نحوۀ روند آموزش شبکه مان را مشاهده کنید.


    خط قرمز در تصویر فوق نشان دهندۀ مثال آموزش مرتبط با 1 است. خط آبی نیز با 0 مرتبط است. عدد مربوط به مثال های آموزشی کنار محور x درج شده اند و مقدار شبکۀ محاسبه شده نیز در راستای محور y درج شده اند. واضح است که هرگاه تعداد اندکی از میله های شبکه (25 عدد یا کمتر) وجود داشته باشند، شبکه بردارهای ورودی متفاوت را تشخیص نمی دهد، و هرگاه تعداد میله ها بیشتر باشند، بطور آشکاری به دو رده تقسیم می شود.

    برآورد عملکرد شبکه

    به منظور ارزیابی تاثیر آموزش، اجازه دهید که از محاسبۀ تابع خطا با روش کوچکترین مربع ها استفاده می کنیم.  برای این منظور، سودمندی را با کد زیر ایجاد کرده و آن را اجرا می کنیم. برای اینکه کار کند به دو فایل نیاز خواهیم داشت: "test.txt" - داده ها و مقادیر دلخواه استفاده شده برای محاسبۀ خطا و "NT.txt" - فایلی که ضرایب برای شبکه را محاسبه کرده است.

    این اسکریپت توالی فعالیت های زیر را انجام می دهد:

    • ایجاد شیء NT از ردۀ 'net'
    • قرائت ضرایب (وزن ها)w و بارگذاری آنها در NT
    • ایجاد آرایه های ورودی ها و خروجی ها شبکه
    • قرائت ورودی ها در یک مدار و قراردادن آنها در آرایۀ  'x' ، قرائت خروجی ها و قراردادن آن در آرایۀ 'reals'
    • محاسبۀ خروجی شبکه، تغذیۀ آرایۀ 'x' به عنوان یک ورودی
    • محاسبۀ error به عنوان مجموع مربع های اختلاف ها بین تمام مقادیر محاسبه شده و مقادیر مورد انتظار (واقعی)
    • پس از رسیدن به انتهای فایل، خطا را نمایش می دهیم و کار اسکریپت را خاتمه می دهیم
    #include "Libraries\NN.ntl" int Run() { net NT; file f; int counter = 0; // Loading weights NT.LoadNetwork("NT.txt"); double error=0; // Declaring an array for storing culculated outputs array <double> CalculatedOutput (L2_Innersize); // Opening a file with test data if(f.Open("test.txt",fmRead|fmText)==false) { System.Print("Input data not found"); return -1; } // Array holds input values array <double> x(inputVectorSize); // Actual output array <double> reals(L2_Innersize); while(true) { for(int i=0;i<inputVectorSize;i++) { x[i]=f.ReadDouble(); if(f.IsEOF()) { System.Print("counter="+counter+"error="+0.5*error+"error/counter="+(0.5*error/counter)); return -1; } } //forming real examples for(int j=0;j<L2_Innersize;j++) { reals[j]=f.ReadDouble(); System.Print("Real exit = "+reals[j]); } CalculatedOutput = NT.Calculate(x,false); System.Print("Calculated exit = "+CalculatedOutput[0]); //calculating error for(uint i=0;i<reals.length();i++) { error+=(reals[i]-CalculatedOutput[i])*(reals[i]-CalculatedOutput[i]); } counter++; } return(0); }

    ایجاد یک شاخص

    اندیکاتوری ایجاد می کنیم که تصمیم شبکه دربارۀ میلۀ بعدی را با استفاده از یک نمودار ستونی نشان می دهد. منطق کار شاخص ساده است. مقدار 0 با مقدار ریزش میلۀ بعدی مرتبط است و مقدار 1 با مقدار صعود و مقدار 0.5 - رویدادهای کاهش و افزایش قیمت بسته شدن به مقدار مساوی ممکن هستند. برای نمایش شاخص در یک پنجرۀ جداگانه، #set_indicator_separate را مشخص خواهیم کرد، همچنین لازم است که فایل که در آن ردۀ 'net' تعیین شده است را مشخص کنیم، ما این فایل را در خط #include "Libraries\NN.ntl" قرار خواهیم داد. ضمناً، اگر فقط یک مقدار خروجی وجود داشته باشد، متغیری برای ذخیرۀ خروجی محاسبه شدۀ شبکه برای ورودی ارائه داده شده نیاز خواهیم داشت، سپس کافی است یک متغییر داشته باشیم اما شبکه می تواند چندین خروجی داشته باشد، در نتیجه، به یک آرایۀ مقادیر نیاز خواهیم داشت: ما این را در خط array CalculatedOutput (L2_Innersize); تعریف می کنیم؛ . در مقدار دهی اولیۀ تابع شاخص مان، پارامترهای شاخص، نوع اش، مقادیر وابستۀ نمودار ستونی با دو مقدار بافر را تعیین خواهیم کرد. ما همچنین باید پارامترهای شبکه مان را بازیابی کنیم یعنی اینکه تمامی ضرایب وزن که در خلال روند آموزش محسابه شده اند را در آن بارگذاری کنیم. این با استفاده از روش LoadNetwork(string s) شیء NT همراه با تنها پارامتر - نام فایل، دربرگیرندۀ ضرایب وزن انجام می شود. ما در تابع Draw ورودی بردار x مرتبط با قیمت های بسته شدن نمودارها را ایجاد می کنیم همراه با شاخص ها [pos+inputVectorSize-1; pos]، که در آن 'pos' برابر است با تعداد میله ای که مقدار را برایش و اندازۀ 'inputVectorSize' بردار ورودی را محاسبه کرده ایم. در آخر، روش 'Calculate'  از شیء NT فراخوانده می شود. این آرایۀ مقادیر را باز می گرداند (اگر شبکه مان چندین خروجی داشته باشد)، اما ازآنجائیکه فقط یک خروجی داریم، از عنصر آرایه با یک شاخص 0 استفاده خواهیم کرد.

    #set_indicator_separate #include "Libraries\NN.ntl" double ExtMapBuffer1[]; double ExtMapBuffer2[]; int ExtCountedBars=0; net NT; array <double> CalculatedOutput (L2_Innersize); int Initialize() { Indicator.SetIndexCount(2); Indicator.SetIndexBuffer(0,ExtMapBuffer1); Indicator.SetIndexStyle(0,2,0,3,0xFF0000); Indicator.SetIndexBuffer(1,ExtMapBuffer2); Indicator.SetIndexStyle(1,2,0,3,0xFF0000); NT.LoadNetwork("NT.txt"); return(0); } int Run() { ExtCountedBars=Indicator.Calculated; if (ExtCountedBars<0) { System.Print("Error"); return(-1); } if (ExtCountedBars>0) ExtCountedBars--; Draw(); return(0); } void Draw() { int pos=Chart.Bars-ExtCountedBars-1; array <double> x(inputVectorSize); while(pos>=0) { ExtMapBuffer1[pos]=0; // forming input vector for(int i=pos+inputVectorSize-1; i>=pos; i--) { x[i-pos]=Close[i]; } ExtMapBuffer2[pos]=NT.Calculate(x,false)[0]; pos--; } }

    نمودار فوق، تخمین شبکه از میلۀ بعدی را نشان می دهد. مقادیر از 0.5 تا 1 نشان می دهد که میلۀ بعدی بیشتر از افت، احتمال صعود خواهد داشت. مقادیر از 0 تا 0.5 به این موضوع اشاره دارند که احتمال ریزش بیشتر از صعود است. مقدار 0.5 وضعیتی دوجنبه را نشان می دهد: ممکن است میلۀ بعدی ریزش داشته باشد یا صعود کند.

    خلاصه

    شبکه های عصبی، ابزارهای قدرتمندی برای تحلیل داده ها به شمار می روند. این مقاله به روند ایجاد یک شبکۀ عصبی با استفاده از برنامۀ نویسی شیء گرا در زبان NTL+ می پردازد. کاربرد برنامه نویسی شی ء گرا این امکان را فراهم می کند که بتوان کد را ساده کرد و آن را در اسکریپت های آینده، بیش از پیش قابل استفادۀ مجدد کرد. در پیاده سازی ارائه داده شده، نیاز داشتیم برای تعریف لایه ای از شبکۀ عصبی، ردۀ layer را ایجاد کنیم و برای تعریف کل شبکه، ردۀ net را ایجاد کنیم. برای شاخص، محاسبۀ  خطا و محاسبۀ وزن های داخلی شبکه، از ردۀ  'net'  استفاده می کنیم. ضمن اینکه، با مثالی از شاخص - نمودار ستونی که پیش بینی شبکه از تغییر قیمت را فراهم می کرد، نحوۀ استفاده از شبکۀ آموزش دیده بیان شد.

Close support
Call to instagram Call to Telegram Call to WhatsApp Call Back