本人在学习计算机视觉,正在学习线性分类器,尝试自己实现一个
一些信息:
- 参数:矢量的数组w,标量的数组b
- R=L2正则项=w0各项平方和到w9各项平方和之和
- 更新参数使用梯度下降算法
- 数据集:cifar-10
- 图像表示:直接将数据转化为矢量xi
- yi=xi对应的类型=0到9中的数
- Li=多类支撑向量机损失=max(0,s(i,j)-s(i,yi)+1)
- N数据数量
- 损失L=L0到LN之和+lambda*R
- 线性分类器:sij=wj点乘xi+bj
由于我没深入学习过线性代数和微积分,所以我想确认的是梯度下降算法是不是这样的:
由于Li=求和 i=0到N max(0,s(i,j)-s(i,yi)+1)
其中当s(i,j)-s(i,yi)+1>0时,max(0,s(i,j)-s(i,yi)+1)导数为
[xi
1
-xi
-1]
所以Li导数只需将这些全判断一次是否大于0,加起来即可
为此,我写了一些千篇一律的函数,其中define D 3072
void add(float a[D], unsigned char b[D]) {
int i;
for (i = 0; i < D; i++) {
a[i] += b[i];
}
}
void add(float a[D], float b[D]) {
int i;
for (i = 0; i < D; i++) {
a[i] += b[i];
}
}
void sub(float a[D], unsigned char b[D]) {
int i;
for (i = 0; i < D; i++) {
a[i] -= b[i];
}
}
void sub(float a[D], float b[D]) {
int i;
for (i = 0; i < D; i++) {
a[i] -= b[i];
}
}
void div(float a[D], float b) {
int i;
for (i = 0; i < D; i++) {
a[i] /= b;
}
}
void mul(float a[D], float b) {
int i;
for (i = 0; i < D; i++) {
a[i] *= b;
}
}
创建了一些用于计算导数的变量,其中define C 10
float wL[C][D] = {};
float bL[C] = {};
float wR[C][D] = {};
在计算损失的同时计算导数
float R() {
int i, j;
float r = 0.0f;
memset(wR, 0, sizeof(wR));
for (i = 0; i < C; i++) {
for (j = 0; j < D; j++) {
r += w[i][j] * w[i][j];
wR[i][j] = w[i][j] * 2 * LA;
}
}
return r;
}
float L() {
int i, j;
float r = 0.0f;
float t = 0.0f;
memset(wL, 0, sizeof(wL));
memset(bL, 0, sizeof(bL));
for (i = 0; i < 50000; i++) {
for (j = 0; j < C; j++) {
if (j == x[i].c) continue;
t = s(i, j) - s(i, x[i].c) + 1;
if (t > 0) {
r += t;
add(wL[j], x[i].x);
bL[j] += 1;
sub(wL[x[i].c], x[i].x);
bL[x[i].c] -= 1;
}
}
}
for (i = 0; i < C; i++) {
div(wL[i], 50000);
bL[i] /= 50000;
add(wL[i], wR[i]);
}
r /= 50000;
return r + R() * LA;
}
最后更新参数(在main函数中),其中LR是学习率
float L1, L2 = 0.0f;
L1 = L();
for (i = 0; i < C; i++) {
mul(wL[i], LR);
sub(w[i], wL[i]);
}
L2 = L();
while (abs(L2 - L1) > 0000000.1) {
L1 = L2;
for (i = 0; i < C; i++) {
mul(wL[i], LR);
sub(w[i], wL[i]);
}
L2 = L();
}