ANN核心数据结构:
typedef
struct
{
int
input_n;
/*
number of input units
*/
int
hidden_n;
/*
number of hidden units
*/
int
output_n;
/*
number of output units
*/
double
*
input_units;
/*
the input units
*/
double
*
hidden_units;
/*
the hidden units
*/
double
*
output_units;
/*
the output units
*/
double
*
hidden_delta;
/*
storage for hidden unit error
*/
double
*
output_delta;
/*
storage for output unit error
*/
double
*
target;
/*
storage for target vector
*/
double
**
input_weights;
/*
weights from input to hidden layer
*/
double
**
hidden_weights;
/*
weights from hidden to output layer
*/
/*
** The next two are for momentum **
*/
double
**
input_prev_weights;
/*
previous change on input to hidden wgt
*/
double
**
hidden_prev_weights;
/*
previous change on hidden to output wgt
*/
} BPNN;
整个神经网络可以分成三层:输入层,隐藏层,输出层,通过加权线性变换,层与层之间的传递,最终得到输入层的实数值。
BPNN
*
bpnn_internal_create(
int
n_in,
int
n_hidden,
int
n_out;)
{
//
创建人工网络,参数分别指定输入层,隐藏层和输出层大小
BPNN
*
newnet;
newnet
=
(BPNN
*
) malloc (
sizeof
(BPNN));
if
(newnet
==
NULL)
{
printf(
"
BPNN_CREATE: Couldn't allocate neural network/n
"
);
return
(NULL);
}
newnet
->
input_n
=
n_in;
//
输入层
newnet
->
hidden_n
=
n_hidden;
//
隐藏层
newnet
->
output_n
=
n_out;
//
输出层
newnet
->
input_units
=
alloc_1d_dbl(n_in
+
1
);
newnet
->
hidden_units
=
alloc_1d_dbl(n_hidden
+
1
);
newnet
->
output_units
=
alloc_1d_dbl(n_out
+
1
);
newnet
->
hidden_delta
=
alloc_1d_dbl(n_hidden
+
1
);
newnet
->
output_delta
=
alloc_1d_dbl(n_out
+
1
);
newnet
->
target
=
alloc_1d_dbl(n_out
+
1
);
//
目标向量
newnet
->
input_weights
=
alloc_2d_dbl(n_in
+
1
, n_hidden
+
1
);
//
输入层到隐藏层的权值
newnet
->
hidden_weights
=
alloc_2d_dbl(n_hidden
+
1
, n_out
+
1
);
//
隐藏层到输出层的权值
newnet
->
input_prev_weights
=
alloc_2d_dbl(n_in
+
1
, n_hidden
+
1
);
newnet
->
hidden_prev_weights
=
alloc_2d_dbl(n_hidden
+
1
, n_out
+
1
);
return
(newnet);
}
下面代码段是ANN运行的核心部分:
if
(train_n
>
0
)
{
//
提供了训练集
printf(
"
Creating new network '%s'/n
"
, netname);
iimg
=
trainlist
->
list[
0
];
//
指向训练集第一张图片
imgsize
=
ROWS(iimg)
*
COLS(iimg);
/*
bthom ===========================
make a net with:
imgsize inputs, 4 hiden units, and 1 output unit
*/
//
输入层为图片大小,隐藏层为,输出层为
net
=
bpnn_create(imgsize,
4
,
1
);
}
//
训练
/*
************* Train it ****************************
*/
for
(epoch
=
1
; epoch
<=
epochs; epoch
++
)
{
printf(
"
%d
"
, epoch); fflush(stdout);
sumerr
=
0.0
;
for
(i
=
0
; i
<
train_n; i
++
)
{
/*
* Set up input units on net with image i *
*/
//
为图像i在网络上建立输入单元
load_input_with_image(trainlist
->
list[i], net);
/*
* Set up target vector for image i *
*/
//
为图像i建立目标向量
load_target(trainlist
->
list[i], net);
/*
* Run backprop, learning rate 0.3, momentum 0.3 *
*/
//
学习速率.3,冲量.3
bpnn_train(net,
0.3
,
0.3
,
&
out_err,
&
hid_err);
sumerr
+=
(out_err
+
hid_err);
}
进行性能评估:
for
(i
=
0
; i
<
n; i
++
)
{
/*
** Load the image into the input layer. *
*/
load_input_with_image(il
->
list[i], net);
//
加载图片到输入层中
/*
** Run the net on this input. *
*/
bpnn_feedforward(net);
//
在当前输入上运行神经网络
/*
** Set up the target vector for this image. *
*/
load_target(il
->
list[i], net);
//
为此图片建立目标向量
/*
** See if it got it right. **
*/
if
(evaluate_performance(net,
&
val,
0
))
{
//
判断是否正确识别,
correct
++
;
}
else
if
(list_errors)
{
printf(
"
%s - outputs
"
, NAME(il
->
list[i]));
for
(j
=
1
; j
<=
net
->
output_n; j
++
)
{
printf(
"
%.3f
"
, net
->
output_units[j]);
}
putchar(
'
/n
'
);
}
err
+=
val;
}
err
=
err
/
(
double
) n;
if
(
!
list_errors)
/*
bthom==================================
this line prints part of the ouput line
discussed in section 3.1.2 of homework
*/
printf(
"
%g %g
"
, ((
double
) correct
/
(
double
) n)
*
100.0
, err);
用到的性能评估函数:
evaluate_performance(BPNN *net,double *err)
{//性能评估
doubledelta;
delta =net->target[1] -net->output_units[1];
*err =(0.5 *delta * delta);
/*** If thetarget unit is on... ***/
if (net->target[1]> 0.5)
{
/*** If theoutput unit is on, then we correctly recognized me! ***/
if (net->output_units[1]> 0.5)
{
return(1);
}
else
{
return(0);
}
/*** Else,the target unit is off... ***/
}
else
{
/*** If theoutput unit is on, then we mistakenly thought it was me ***/
if (net->output_units[1]> 0.5)
{
return(0);
/***else, we correctly realized that it wasn't me ***/
}
else
{
return(1);
}
}
}
辅助处理函数区:
load_input_with_image(IMAGE
*
img, BPNN
*
net)
{
//
输入图像
double
*
units;
int
nr, nc, imgsize, i, j, k;
nr
=
ROWS(img);
//
行大小
nc
=
COLS(img);
//
列大小
imgsize
=
nr
*
nc;;
if
(imgsize
!=
net
->
input_n)
{
//
确保输入单元数目设置为图片大小
printf(
"
LOAD_INPUT_WITH_IMAGE: This image has %d pixels,/n
"
, imgsize);
printf(
"
but your net has %d input units. I give up./n
"
, net
->
input_n);
exit (
-
1
);
}
//
取图片的每个像素为输入单元
units
=
net
->
input_units;
k
=
1
;
for
(i
=
0
; i
<
nr; i
++
)
{
for
(j
=
0
; j
<
nc; j
++
)
{
units[k]
=
((
double
) img_getpixel(img, i, j))
/
255.0
;
k
++
;
}
}
}
load_target(IMAGE
*
img, BPNN
*
net)
{
//
加载目标值
int
scale;
char
userid[
40
], head[
40
], expression[
40
], eyes[
40
], photo[
40
];
userid[
0
]
=
head[
0
]
=
expression[
0
]
=
eyes[
0
]
=
photo[
0
]
=
'
/0
'
;
/*
** scan in the image features **
*/
sscanf(NAME(img),
"
%[^_]_%[^_]_%[^_]_%[^_]_%d.%[^_]
"
,
userid, head, expression, eyes,
&
scale, photo);
if
(
!
strcmp(userid,
"
glickman
"
))
{
net
->
target[
1
]
=
TARGET_HIGH;
/*
it's me, set target to HIGH
*/
}
else
{
net
->
target[
1
]
=
TARGET_LOW;
/*
not me, set it to LOW
*/
}
}
void
bpnn_train(BPNN
*
net,
double
eta, momentum
*
eo, momentum
*
eh)
{
//
人工神经网络训练
int
in
, hid,
out
;
double
out_err, hid_err;
in
=
net
->
input_n;
hid
=
net
->
hidden_n;
out
=
net
->
output_n;
/*
** Feed forward input activations. **
*/
bpnn_layerforward(net
->
input_units, net
->
hidden_units,
net
->
input_weights,
in
, hid);
bpnn_layerforward(net
->
hidden_units, net
->
output_units,
net
->
hidden_weights, hid,
out
);
/*
** Compute error on output and hidden units. **
*/
bpnn_output_error(net
->
output_delta, net
->
target, net
->
output_units,
out
,
&
out_err);
bpnn_hidden_error(net
->
hidden_delta, hid, net
->
output_delta,
out
,net
->
hidden_weights, net
->
hidden_units,
&
hid_err);
*
eo
=
out_err;
*
eh
=
hid_err;
/*
** Adjust input and hidden weights. **
*/
bpnn_adjust_weights(net
->
output_delta,
out
, net
->
hidden_units, hid,net
->
hidden_weights, net
->
hidden_prev_weights, eta, momentum);
bpnn_adjust_weights(net
->
hidden_delta, hid, net
->
input_units,
in
,net
->
input_weights, net
->
input_prev_weights, eta, momentum);
}
void
bpnn_feedforward(BPNN
*
net)
{
//
前向反馈
int
in
, hid,
out
;
in
=
net
->
input_n;
//
输入层大小
hid
=
net
->
hidden_n;
//
隐藏层大小
out
=
net
->
output_n;
//
输出层大小
/*
** Feed forward input activations. **
*/
bpnn_layerforward(net
->
input_units, net
->
hidden_units,net
->
input_weights,
in
, hid);
bpnn_layerforward(net
->
hidden_units, net
->
output_units,net
->
hidden_weights, hid,
out
);
}
void
bpnn_adjust_weights(
double
*
delta,
double
*
ly,
double
**
w,
double
**
oldw,
double
eta,
double
momentum)
{
//
调整权值
double
new_dw;
int
k, j;
ly[
0
]
=
1.0
;
for
(j
=
1
; j
<=
ndelta; j
++
)
{
for
(k
=
0
; k
<=
nly; k
++
)
{
new_dw
=
((eta
*
delta[j]
*
ly[k])
+
(momentum
*
oldw[k][j]));
w[k][j]
+=
new_dw;
oldw[k][j]
=
new_dw;
}
}
}
void
bpnn_layerforward(
double
*
l1,
double
*
l2,
double
**
conn,
int
n1,
int
n2)
{
//
层次前向输入
double
sum;
int
j, k;
/*
** Set up thresholding unit **
*/
l1[
0
]
=
1.0
;
//
加权线性变换
/*
** For each unit in second layer **
*/
for
(j
=
1
; j
<=
n2; j
++
)
{
/*
** Compute weighted sum of its inputs **
*/
sum
=
0.0
;
for
(k
=
0
; k
<=
n1; k
++
)
{
sum
+=
conn[k][j]
*
l1[k];
}
l2[j]
=
squash(sum);
}
}