Lớp KohonenNetwork

Một phần của tài liệu Luận văn tốt nghiệp cử nhân CNTT nhận dạng ký tự ảnh (Trang 50)

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 ;

length = vectorLength ( input ) ;

// Điều chỉnh trong trường hợp độ dài quá nhỏ 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 */

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 ) ;

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[])

{

int i, win=0;

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) ;

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 ;

} 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 ; rate = learnRate ; 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++;

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 ( 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 ;

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] ;

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ố.

Danh sách 2.19: Hiệu chỉnh các trọng số (KohonenNetwork.java) /**

* Phương thức này được gọi vào cuối mỗi lần huấn luyện, và nó điều chỉnh các trọng số dựa vào lần thử trước.

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

* @Tham số learn_method sử dụng phương pháp method(0=ađitive, 1=subtractive)

* @Tham số won quản lý số lần mỗi nơron thắng * @Tham số bigcorr dùng để quản lý sai số

* @Tham số correc dùng để quản lý mảng hiệu chỉnh */ void adjustWeights ( double rate , int learn_method , int won[] , double bigcorr[], double correc[][] ) {

double corr, cptr[], wptr[], length, f ;

bigcorr[0] = 0.0 ;

for ( int i=0 ; i<outputNeuronCount ; i++ ) { if ( won[i]==0 )

continue ;

cptr = correc[i];

f = 1.0 / (double) won[i] ; if ( learn_method!=0 )

f *= rate ;

length = 0.0 ;

for ( int j=0 ; j<=inputNeuronCount ; j++ ) { corr = f * cptr[j] ;

wptr[j] += corr ; length += corr * corr ; }

if ( length > bigcorr[0] ) bigcorr[0] = length ; }

// Tính toán nhân tố hiệu chỉnh

bigcorr[0] = Math.sqrt ( bigcorr[0] ) / rate ; }

2.4 Kết luận

Trong chương này, chúng ta đã tìm hiểu về mạng nơron Kohonen. Mạng nơron Kohonen khác với mạng lan truyền ngược ở vài điểm. Mạng nơron Kohonen là luyện không giám sát. Điều này có nghĩa rằng, mạng nơron Kohonen được cho dữ liệu đầu vào nhưng không biết trước được “cái ra”. Sau đó, trong khi huấn luyện thì mạng nơron Kohonen bắt đầu vẽ lên bản đồ của mỗi nơron trong mẫu huấn luyện, mẫu này bao gồm các nơron đầu rạ

Một mạng nơron Kohonen chỉ bao gồm hai lớp. Mạng được đưa vào một mẫu dữ liệu đầu vào và coi đây là lớp dữ liệu vàọ Mẫu dữ liệu đầu vào này phải được chuẩn hóa thành các giá trị nằm trong khoảng [-1,1]. Dữ liệu đầu ra từ mạng nơron này là nơron đầu ra thắng riêng lẻ. Các nơron đầu ra có thể được đưa lại vào trong các nhóm, tương ứng với các nhóm mà mạng nơron Kohonen đã phân loại đối với đầu vàọ

Sự huấn luyện một mạng nơron Kohonen khác đáng kể so với thuật toán lan truyền ngược đã được giới thiệụ Để huấn luyện một mạng nơron Kohonen, chúng ta phải đưa vào cho nó các phần tử huấn luyện và xem nơron đầu ra là nơron thắng. Để cho các nơron thắng thì các trọng số của nơron thắng này được sửa đổi sao cho nó sẽ hoạt động cao hơn trên mẫụ

Cũng có trường hợp có thể có một hoặc vài nơron không bao giờ thắng. Như vậy, sẽ có các nơron có trọng số chết được đưa đến mạng nơron. Điều này sẽ gây

cho mạng làm việc quá tải khi nhận dạng, và thường thất bại khi giá trị trên các nơron đầu ra ngang nhaụ

Trong chương tiếp theo chúng ta sẽ áp dụng mạng nơron Kohonen vào ứng dụng thực tế, đó là ứng dụng nhận dạng ký tự quang (cụ thể là chữ viết tay bằng chuột và chữ ký đưa và dưới dạng ảnh).

Chương 3. Nhận dạng ký tự quang sử dụng mạng nơron Kohonen

Nhận dạng luôn là một phần quan trọng và thú vị trong các ứng dụng tin học hiện naỵ Nhận dạng chữ viết cũng như nhận dạng nói chung là dùng thuật toán để tìm ra các đặc điểm riêng của từng cá thể trong quần thể mà chúng ta phải nhận dạng. Đối với nhận dạng ký tự quang thì với mỗi dữ liệu nhập vào (có thể là ký tự viết bằng chuột hay chữ ký được scan), ta sẽ phải tìm ra được đầu ra tương ứng với nó.

Máy Scanner là một loại máy scan phẳng (Flatbed Scanner) dùng để scan những tài liệu đơn lẻ như văn bản, hình ảnh, thẻ, CMND…

Một phần của tài liệu Luận văn tốt nghiệp cử nhân CNTT nhận dạng ký tự ảnh (Trang 50)

Tải bản đầy đủ (PDF)

(68 trang)