Điều chỉnh các trọng số (cập nhật trọng số)

Một phần của tài liệu Tìm hiểu mạng kohonen và cài đặt ứng dụng (Trang 31 - 51)

Một công đoạn xuất hiện khi dữ liệu huấn luyện được đưa vào mạng nơron Kohonen, và các trọng số được điều chỉnh dựa trên các kết quả của dữ liệu huấn luyện. Sự điều chỉnh các trọng số sẽ làm cho mạng có thuận lợi hơn ngay sau khi nó được đưa trở lại mạng. Ma trận trọng số cuối cùng được sử dụng sẽ là ma trận tốt nhất được xác định từ mỗi chu kỳ. Bây giờ, chúng ta sẽ xem xét các trọng số này được thay đổi như thế nàọ

Phương pháp cho việc tính toán thay đổi các trọng số sử dụng phương trình sau: ) ( 1 t t t w x w w+ = +α − (2.48)

Biến x là vector huấn luyện được đưa vào mạng. Biến wt là trọng số của nơron thắng, và biến wt+1 là trọng số mới, α là hệ số học.

10.Tính toán sai số

Khi mạng huấn luyện không giám sát bao giờ cũng có sai số, đó là sự khác nhau giữa kết quả mong đợi và kết quả thực tế của mạng nơron. Sai số mà chúng ta tính toán là những cái mà không đúng giữa kết quả mong đợi và kết quả thực tế.

ej = ||x-wj||

Mục đích của mạng nơron Kohonen là phân loại dữ liệu đầu vào vào trong các tập khác nhau, cho nên sai số của mạng nơron Kohonen phải được đo lường. Sai số này sẽ được tính toán trong quá trình huấn luyện mạng.

IỊ Thực thi mạng nơron Kohonen

Có vài lớp có thể được sử dụng cùng nhau để tạo ra một mạng nơron Kohonen. Các lớp được mô tả như sau:

· KohonenNetwork – Thực thi các phương thức thuộc về mạng nơron Kohonen. Đây là nơi mà mạng nơron Kohonen được huấn luyện và lấy các mẫụ

· Network – Chứa đựng các phương pháp không thuộc về mạng nơron Kohonen. Các lớp này chứa các phương pháp để tính toán tích vô hướng, và chiều dài vector.

· NeuralReportable – Một giao diện đơn giản cho phép mạng nơron Kohonen trả về thông tin tiến bộ sau khi mạng nơron được huấn luyện.

· TrainingSet – Một tập huấn luyện chứa đối tượng, đó là có thể chứa các mảng của các lần huấn luyện riêng lẻ. Tập huấn luyện có thể chứa cả các phần tử dữ liệu đầu vào và dữ liệu đầu rạ

Các lớp này hoạt động cùng nhau để cung cấp các chức năng cho mạng Kohonen.

1. Các tập huấn luyện

Để huấn luyện mạng nơron Kohonen thì các tập huấn luyện phải được cung cấp. Dữ liệu huấn luyện này sẽ được lưu trữ trong lớp TrainingSet, lớp này được thiết kế để nó là một lớp chứa đựng dữ liệụ Lớp TrainingSet quản lý hai biến mảng độ dài của đầu vào và đầu rạ

import javạiọ*; import javạutil.*;

protected int inputCount; protected int outputCount; protected double input[][]; protected double output[][]; protected int trainingSetCount;

TrainingSet ( int inputCount , int outputCount ) {

this.inputCount = inputCount; this.outputCount = outputCount; trainingSetCount = 0;

}

public int getInputCount() {

return inputCount; }

public int getOutputCount() {

return outputCount; }

public void setTrainingSetCount(int trainingSetCount) {

this.trainingSetCount = trainingSetCount;

input = new double[trainingSetCount][inputCount]; output = new double[trainingSetCount][outputCount]; classify = new double[trainingSetCount];

}

public int getTrainingSetCount() {

return trainingSetCount; } (adsbygoogle = window.adsbygoogle || []).push({});

void setInput(int set,int index,double value) throws RuntimeException

{

if ( (set<0) || (set>=trainingSetCount) )

if ( (index<0) || (index>=inputCount) )

throw(new RuntimeException("Training input index out of range:" + index )); input[set][index] = value;

}

void setOutput(int set,int index,double value) throws RuntimeException

{

if ( (set<0) || (set>=trainingSetCount) )

throw(new RuntimeException("Training set out of range:" + set )); if ( (index<0) || (set>=outputCount) )

throw(new RuntimeException("Training input index out of range:" + index )); output[set][index] = value;

}

double getInput(int set,int index) throws RuntimeException

{

if ( (set<0) || (set>=trainingSetCount) )

throw(new RuntimeException("Training set out of range:" + set )); if ( (index<0) || (index>=inputCount) )

throw(new RuntimeException("Training input index out of range:" + index )); return input[set][index];

}

double getOutput(int set,int index) throws RuntimeException

{

if ( (set<0) || (set>=trainingSetCount) )

throw(new RuntimeException("Training set out of range:" + set )); if ( (index<0) || (set>=outputCount) )

throw(new RuntimeException("Training input index out of range:" + index )); return output[set][index];

}

double []getOutputSet(int set) throws RuntimeException

{

if ( (set<0) || (set>=trainingSetCount) )

throw(new RuntimeException("Training set out of range:" + set )); return output[set];

double []getInputSet(int set) throws RuntimeException {

if ( (set<0) || (set>=trainingSetCount) ) (adsbygoogle = window.adsbygoogle || []).push({});

throw(new RuntimeException("Training set out of range:" + set )); return input[set];

}} }

Trong lớp TrainingSet, nó lưu trữ các biến và cách sử dụng chúng được tóm tắt như sau:

• inputCount - Số lượng các phần tử đầu vào sẽ có cho từng mẫu huấn luyện. • outputCount - Số lượng các phần tử đầu ra sẽ có cho từng mẫu huấn luyện. • input[][] - Các mẫu đầu vào huấn luyện.

• output[][] - Các mẫu đầu ra huấn luyện. • trainingSetCount - Số lượng mẫu huấn luyện.

Do quá trình hoạt động của mạng nơron Kohonen là không có giám sát, chỉ có các phần tử dữ liệu đầu vào được cung cấp, nên đối tượng TrainingSet được xây dựng để huấn luyện cho ra dữ liệu đầu ra, nó sẽ được chuyển tới đối tượng KohonenNetwork để huấn luyện trong lần tiếp theọ

2. Báo cáo tiến trình

Để chuẩn bị các tập huấn luyện và thu nhận tình trạng thông tin từ quá trình huấn luyện, ta phải hiểu rõ các lớp mạng Kohonen hoạt động như thế nàọ Chúng ta sẽ bắt đầu bằng việc xem xét lớp mạng cơ sở.

a) Lớp mạng cơ sở

Bây giờ chúng ta sẽ xem xét lớp Network. Lớp này là lớp cơ sở cho lớp KohonenNetwork, nó là lớp cuối cùng cung cấp cho mạng nơron Kohonen.

Việc tính toán chiều dài một vector là một phần quan trọng của mạng nơron Kohonen. Lớp Network chứa một phương thức để tính toán độ dài vector của vector

đã cho, và nó được biểu diễn dưới dạng mảng. Phương thức này được chỉ ra trong danh sách 2.7.

Danh sách 2.7: Tính độ dài của một vector (Network.java) /**

* @Tham số v vector

* @Kết quả trả về độ dài vector. */

static double vectorLength( double v[] ) {

double rtn = 0.0 ;

for ( int i=0;i<v.length;i++ ) rtn += v[i] * v[i];

return rtn; }

Một chức năng quan trong khác được cung cấp bởi lớp cơ sở Network là chức năng tính toán tích vô hướng. Lớp Network của mạng Kohonen dùng phương thức này để tính toán dữ liệu đầu ra của mạng nơron. Phương thức tính tích vô hướng được chỉ ra trong danh sách 2.8.

Danh sách 2.8: Tính toán tích vô hướng (Network.java) /**

* @Tham số vec1 là vector thứ nhất * @Tham số vec2 là vector còn lại * @Kết quả trả về là tích vô hướng. */

double dotProduct(double vec1[] , double vec2[] ) { int k,v; double rtn; rtn = 0.0; k = vec1.length; v = 0; while ( (k--)>0 ) { rtn += vec1[v] * vec2[v]; v++; }

Đầu tiên, các trọng số giữa nơron được khởi tạo với các giá trị ngẫu nhiên. Sau đó các giá trị ngẫu nhiên này được huấn luyện để cho ra các kết quả tốt hơn. Tại thời điểm bắt đầu của mỗi chu kỳ huấn luyện, các trọng số cũng được khởi tạo với các giá trị ngẫu nhiên. Lớp Network cung cấp một phương thức để thực thi vấn đề nàỵ Danh sách 2.9 chỉ ra phương thức để sinh các trọng số ngẫu nhiên.

Danh sách 2.9: Khởi tạo các trọng số ngẫu nhiên (Network.java) /**

* @Tham số weight là một ma trận trọng số. */

void randomizeWeights( double weight[][] ) {

double r ;

int temp = (int)(3.464101615 / (2. * Math.random() )); for ( int y=0;y<weight.length;y++ ) {

for ( int x=0;x<weight[0].length;x++ ) { (adsbygoogle = window.adsbygoogle || []).push({});

r = (double) random.nextInt(Integer.MAX_VALUE) + (double) random.nextInt(Integer.MAX_VALUE) -

(double) random.nextInt(Integer.MAX_VALUE) - (double) random.nextInt(Integer.MAX_VALUE) ; weight[y][x] = temp * r ; } } } } b) Lớp KohonenNetwork

Chúng ta sẽ xem xét lớp KohonenNetwork. Lớp này là lớp thực thi mạng nơron Kohonen. Lớp KohonenNetwork có một số tính chất được chỉ ra trong danh sách 2.10.

Danh sách 2.10: Các tính chất của lớp KohonenNetwork public class KohonenNetwork extends Network {

double outputWeights[][]; protected int learnMethod = 1; protected double learnRate = 0.5; protected double quitError = 0.1; protected int retries = 10000;

protected double reduction = .99; protected NeuralReportable owner; public boolean halt = false; protected TrainingSet train;

Các tính chất được mô tả như sau:

• halt – Thiết lập này là xác thực hủy bỏ quá trình huấn luyện.

• learnMethod – Tỷ lệ học, đặt bằng 1.

• learnRate – Tỷ lệ học ban đầụ

• outputWeights[][] – Các trọng số của các nơron đầu ra dựa trên đầu vàọ

• owner – Lớp owner, lớp này thực thi giao diện NeuralReportablẹ

• quitError – Khi tỷ lệ sai số đạt đến mức nhỏ hơn 10% thì dừng huấn luyện.

• reduction – Lượng giảm tỷ lệ học ban đầu (learnRate) bởi mỗi công đoạn.

• retries - Tổng số chu kỳ cho phép, nó đặt một mức trần (a ceiling) số lượng các chu kỳ huấn luyện có thể xảy rạ

• train – Tập huấn luyện.

Để cho mạng nơron Kohonen hoạt động tốt, ta không chỉ chuẩn hóa vector đầu vào, mà ta còn phải chuẩn hóa cả ma trận trọng số. Danh sách 2.13 chỉ ra một phương thức để chuẩn hóa các dữ liệu đầu vào để đưa tới mạng nơron Kohonen, và danh sách 2.14 chỉ ra sự chuẩn hóa ma trận trọng số.

Danh sách 2.13: Chuẩn hó dữ liệu đầu vào (KohonenNetwork.java) /**

* @Tham số input là mẫu dữ liệu vào * @Tham số normfac là nhân tố chuẩn hóa

* @Tham số synth là giá trị đầu vào cuối cùng */

void normalizeInput(

final double input[] , double normfac[] ,

double synth[] )

{

double length, d ;

if ( length < 1.E-30 ) length = 1.E-30 ;

normfac[0] = 1.0 / Math.sqrt ( length ) ; synth[0] = 0.0 ;

}

Danh sách 2.14: Chuẩn hóa trọng số (KohonenNetwork.java) /**

* @Tham số w là các trọng số đầu vào */ (adsbygoogle = window.adsbygoogle || []).push({});

void normalizeWeight( double w[] ) {

int i ; double len ;

len = vectorLength ( w ) ;

// Điều chỉnh trong trường hợp độ dài quá nhỏ if ( len < 1.E-30 )

len = 1.E-30 ;

len = 1.0 / Math.sqrt ( len ) ;

for ( i=0 ; i<inputNeuronCount ; i++ ) w[i] *= len ;

w[inputNeuronCount] = 0; }

Bây giờ ta kiểm tra phương thức thử mẫu, được sử dụng để đưa mẫu dữ liệu đầu vào tới mạng nơron Kohonen. Phương pháp này được gọi là phương pháp thử “trial”, được chỉ ra trong danh sách 2.15.

Danh sách 2.15: Thử mẫu vào (KohonenNetwork.java) /**

* Phương thức này có thể được sử dụng khi đưa một mẫu tới mạng. * Thường thường, nó hay dùng để gọi nơron thắng

* @Tham số input là mẫu vàọ */

void trial ( double input[] ) {

int i ;

double normfac[]=new double[1], synth[]=new double[1], optr[]; normalizeInput(input,normfac,synth) ;

for ( i=0 ; i<outputNeuronCount; i++ ) { optr = outputWeights[i];

output[i] = dotProduct( input , optr ) * normfac[0] + synth[0] * optr[inputNeuronCount] ; // Tạo bản đồ lưỡng cực mới (từ -1,1 tới 0,1) output[i] = 0.5 * (output[i] + 1.0) ; // Tính toán làm tròn if ( output[i] > 1.0 ) output[i] = 1.0 ; if ( output[i] < 0.0 ) output[i] = 0.0 ; } }

Vậy quá trình tính toán giá trị cho mỗi nơron đầu ra được tính toán bằng cách lấy tích vô hướng đã được chuẩn hóa của dữ liệu đầu vào và các trọng số. Do dữ liệu đầu ra cuối cùng có thể lớn hơn 1 hoặc nhỏ hơn 0, ta phải đưa nó về khoảng [0,1]. Để đưa dữ liệu đầu ra về khoảng [0,1] thì các kết quả nhỏ hơn 0 thì ta đưa nó về 0, và các kết quả lớn hơn 1 được đưa về 1. Dữ liệu đầu ra cuối cùng của mỗi nơron được lưu trữ trong mảng dữ liệu đầu rạ

Chúng ta chỉ quan tâm đến nơron thắng vì chúng được đưa lại vào mẫu để huấn luyện. Danh sách 2.16 chỉ ra phương thức để đưa một mẫu dữ liệu đầu vào tới mạng Kohonen, và thu nhận nơron thắng. Phương thức này chính là phương thức dùng để phận loại mẫu trong mạng Kohonen.

Danh sách 2.16: Đưa ra một mẫu vào và thu nhận nơron thắng /**

* @Tham số input là mẫu vào

* @Tham số normfac là nhân tố chuẩn hóa

* @Tham số synth là giả đầu vào cuối cùng – (synthetic last input)

* @Kết quả trả về là số nơron thắng. */

public int winner(double input[] ,double normfac[] ,double synth[])

double biggest, optr[];

normalizeInput( input , normfac , synth ) ; // Chuẩn hóa dữ liệu đầu vào

biggest = -1.E30;

for ( i=0 ; i<outputNeuronCount; i++ ) { optr = outputWeights[i];

output[i] = dotProduct (input , optr ) * normfac[0] + synth[0] * optr[inputNeuronCount] ; // Tạo bản đồ lưỡng cực mới (từ -1,1 tới 0,1) output[i] = 0.5 * (output[i] + 1.0) ; (adsbygoogle = window.adsbygoogle || []).push({});

if ( output[i] > biggest ) { biggest = output[i] ; win = i ;

}

// account for rounding if ( output[i] > 1.0 ) output[i] = 1.0 ; if ( output[i] < 0.0 ) output[i] = 0.0 ; } return win ; }

Phương thức này sẽ thường xuyên được sử dụng khi ta muốn đưa một mẫu tới một mạng nơron để phân loạị Còn phương thức “thử” mà chúng ta vừa xem xét ở trên chỉ được sử dụng trong khi huấn luyện mạng. Khi huấn luyện, chúng ta quan tâm đến dữ liệu đầu ra hiện tại của mỗi nơron. Trái lại, khi phân loại mẫu thì chúng ta chỉ quan tâm đến nơron thắng.

Phương thức winner lặp qua mỗi nơron đầu ra và tính toán dữ liệu đầu ra cho mỗi nơron riêng biệt. Trong quá trình lặp này thì các chỉ số của nơron được lưu lạị Chỉ số này là của nơron có giá trị đầu ra cao nhất. Nơron có chỉ số cao nhất được gọi là nơron thắng. Nơron thắng này được trả về tập mẫu để tiếp tục tham gia vào quá trình huấn luyện.

Bây giờ chúng ta bắt đầu xem xét quá trình huấn luyện. Phương thức training

được chỉ ra trong danh sách 2.17.

Danh sách 2.17: Huấn luyện mạng nơron (KohonenNetwork.java) /**

* @exception javạlang.RuntimeException */

public void learn () throws RuntimeException {

int i, key, tset,iter,n_retry,nwts; int won[],winners ;

double work[],correc[][],rate,best_err,dptr[]; double bigerr[] = new double[1] ;

double bigcorr[] = new double[1];

KohonenNetwork bestnet; // Preserve best here totalError = 1.0 ;

bestnet = new

KohonenNetwork(inputNeuronCount,outputNeuronCount,owner) ; won = new int[outputNeuronCount];

correc = new double[outputNeuronCount][inputNeuronCount+1]; if ( learnMethod==0 )

work = new double[inputNeuronCount+1]; else work = null ; rate = learnRate; initialize () ; best_err = 1.e30 ; // Vòng lặp chính: n_retry = 0 ;

for ( iter=0 ; ; iter++ ) {

evaluateErrors ( rate , learnMethod , won , bigerr , correc , work ) ;

totalError = bigerr[0] ;

if ( totalError < best_err ) { best_err = totalError ;

copyWeights ( bestnet , this ) ; } winners = 0 ; for ( i=0;i<won.length;i++ ) if ( won[i]!=0 ) winners++; if ( bigerr[0] < quitError ) break ;

if ( (winners < outputNeuronCount) && (winners < train.getTrainingSetCount()) ) { forceWin ( won ) ;

continue ; }

adjustWeights ( rate , learnMethod , won , bigcorr, correc ) ; owner.update(n_retry,totalError,best_err); if ( halt ) { owner.update(n_retry,totalError,best_err); break; } Thread.yield(); if ( bigcorr[0] < 1E-5 ) { if ( ++n_retry > retries ) break ; initialize () ; iter = -1 ;

continue ; } if ( rate > 0.01 ) rate *= reduction ; } // Hoàn thành

copyWeights( this , bestnet ) ;

for ( i=0 ; i<outputNeuronCount ; i++ ) normalizeWeight ( outputWeights[i] ) ; halt = true;

n_retry++; (adsbygoogle = window.adsbygoogle || []).push({});

owner.update(n_retry,totalError,best_err); }

Phương thức training bắt đầu bằng việc khởi tạo các ma trận trọng số với các giá trị ngẫu nhiên và điều chỉnh các giá trị trọng yếu khác. Khi khởi tạo xong, vòng lặp chính đưa các mẫu huấn luyện tới mạng nơron và tính toán các sai số dựa trên các kết quả thu được từ mạng nơron. Khi kết thúc vòng lặp chính, xác định được nơron thắng, và nó sẽ tiếp tục huấn luyện để thúc đẩy hợp nhất các khả năng của nó trong quá trình nhận dạng mẫu riêng biệt, đồng thời cho ra một ma trận trọng số tốt hơn. Điều này được xác định bằng cách tính toán sự cải tiến sai số giữa công đoạn hiện tại và công đoạn trước. Nếu sự cải tiến không đáng kể thì chu kỳ huấn luyện này coi như hoàn thành, và lại bắt đầu một chu kỳ mớị

Vì chu kỳ huấn luyện cực nhanh nên chúng ta chỉ theo dõi chu kỳ có tỷ lệ sai số tốt nhất. Khi chúng ta tìm thấy một ma trận trọng số có sai số nằm dưới mức sai số cho phép, thì sự huấn luyện được hoàn thành. Ngược lại, thì chúng ta sẽ lấy ma trận tốt nhất đã được xác định ở chu kỳ trước.

Bây giờ, chúng ta sẽ bắt đầu xem xét xem các sai số được ước lượng như thế nàọ Danh sách 2.18 chỉ ra ước lượng các sai số.

Danh sách 2.18: Ước lượng các sai số (KohonenNetwork.java) /**

* Phương thức này dùng trong quá trình học. Nó dùng để ước lượng các trọng số dựa vào tập huấn luyện.

* @Tham số rate là tỉ lệ học

* @Tham số learn_method là dùng phương thức method(0=ađitive, 1=subtractive)

* @Tham số won là quản lý số lần nơron thắng * @Tham số bigerr là trả về sai số

* @Tham số correc là trả về mảng hiệu chỉnh * @Tham số work là phạm vi hoạt động

* @exception javạlang.RuntimeException */

*/ void evaluateErrors ( void evaluateErrors ( double rate , int learn_method , int won[], double bigerr[] , double correc[][] , double work[]) throws RuntimeException {

int best, size,tset ;

double dptr[], normfac[] = new double[1];

double synth[]=new double[1], cptr[], wptr[], length, diff ; // Hiệu chỉnh và đặt lại số lần thắng

for ( int y=0;y<correc.length;y++ ) { for ( int x=0;x<correc[0].length;x++ ) { correc[y][x]=0;

} } }

for ( int i=0;i<won.length;i++ ) won[i]=0;

bigerr[0] = 0.0 ;

// Lặp qua tất cả các tập huấn luyện để xác định giá trị hiệu chỉnh for ( tset=0 ; tset<train.getTrainingSetCount(); tset++ ) { dptr = train.getInputSet(tset);

best = winner ( dptr , normfac , synth ) ; won[best]++;

wptr = outputWeights[best]; cptr = correc[best];

length = 0.0 ;

for ( int i=0 ; i<inputNeuronCo the unt ; i++ ) { diff = dptr[i] * normfac[0] - wptr[i] ;

length += diff * diff ; if ( learn_method!=0 ) cptr[i] += diff ; else

work[i] = rate * dptr[i] * normfac[0] + wptr[i] ; }

diff = synth[0] - wptr[inputNeuronCount] ; length += diff * diff ;

if ( learn_method!=0 )

cptr[inputNeuronCount] += diff ; else

work[inputNeuronCount] = rate * synth[0] + wptr[inputNeuronCount] ; (adsbygoogle = window.adsbygoogle || []).push({});

if ( length > bigerr[0] ) bigerr[0] = length ; if ( learn_method==0 ) { normalizeWeight( work ) ;

for ( int i=0 ; i<=inputNeuronCount ; i++ ) cptr[i] += work[i] - wptr[i] ;

} } }

bigerr[0] = Math.sqrt ( bigerr[0] ) ; }

Mạng được huấn luyện và tạo ra một mảng hiệu chỉnh chứa biến hiệu chỉnh được tạo bởi phương thức adjustWeights.

Sau khi nhân tố hiệu chỉnh được tính toán, thì các trọng số phải được điều chỉnh. Danh sách 2.19 chỉ ra việc điều chỉnh các trọng số.

Một phần của tài liệu Tìm hiểu mạng kohonen và cài đặt ứng dụng (Trang 31 - 51)