
























#include "global_define.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define M_PI 3.14159265358979323846double normal_random() {
double u1 = rand() / (RAND_MAX + 1.0);
double u2 = rand() / (RAND_MAX + 1.0);
double z = sqrt(-2.0 * log(u1)) * sin(2.0 * M_PI * u2);
return z;
}
struct Pair {
double* first;
double second;
};
typedef struct Pair Pair;
const int iterations = 40000;
const int log_step = 50;
double learningrate = 0.00125;
double data[SIZE][LABELS];
double train_data[TRAIN_SIZE][LABELS];
double maximums[LABELS] = { 0.0 };
double minimums[LABELS] = { 0.0 };
double avgs[LABELS] = { 0.0 };
int init = 0;
double w[DATA_SIZE] = {
1.76405235,
0.40015721,
0.97873798,
2.2408932,
1.86755799,
-0.97727788,
0.95008842,
-0.15135721,
-0.10321885,
0.4105985,
0.14404357,
1.45427351,
0.76103773, };
double b = 0;
////////////////////////////
#include "array.h"
#include "dataprocess.h"
#include "Network.h"
#include "vectorcomputation.h"
////////////////////////////
int main() {
printhello(1);
load_data();
//数据集 TRAIN_SIZE * SIZE
double x[TRAIN_SIZE][DATA_SIZE];
//double** x = (double**)malloc(sizeof(double*) * TRAIN_SIZE);
//for (int i = 0; i < TRAIN_SIZE; i++) {
// x[i] = (double*)malloc(SIZE * sizeof(double));
//}
for (int i = 0; i < TRAIN_SIZE; i++) {
for (int j = 0; j < DATA_SIZE; j++) {
x[i][j] = train_data[i][j];
}
}
//标签集 TRAIN_SIZE * 1
double y[TRAIN_SIZE];
//double* y = (double*)malloc(sizeof(double) * TRAIN_SIZE);
for (int i = 0; i < TRAIN_SIZE; i++) {
y[i] = train_data[i][DATA_SIZE];
}
__init__();
printf("按下任意按键以开始训练...\n");
system("pause");
train(x, y);
return 0;
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
////////////////////////////////__ARRAY_H__//////////////////////////////////
double getsum(const double* arr, const int size) {
double ans = 0;
for (int i = 0; i < size; i++) {
ans += arr[i];
}
return ans;
}
double getavg(const double* arr, const int size) {
return getsum(arr, size) / (double)size;
}
double getmax_col(const double arr[TRAIN_SIZE][LABELS], const int col) {
double ans = -23333;
for (int i = 0; i < TRAIN_SIZE; i++) {
if (arr[i][col] > ans) {
ans = arr[i][col];
}
}
return ans;
}
double getmin_col(const double arr[TRAIN_SIZE][LABELS], const int col) {
double ans = 23333;
for (int i = 0; i < TRAIN_SIZE; i++) {
if (arr[i][col] < ans) {
ans = arr[i][col];
}
}
return ans;
}
double getsum_row(const double arr[TRAIN_SIZE][LABELS], const int col) {
double ans = 0;
for (int i = 0; i < TRAIN_SIZE; i++) {
ans += arr[i][col];
}
return ans;
}
double getavg_col(const double arr[TRAIN_SIZE][LABELS], const int col) {
return getsum_row(arr, col) / (double)TRAIN_SIZE;
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////__DATAPROCESS_H__///////////////////////////////
void load_data() {
printf("开始载入数据...\n");
const char* datafile = "train.data";
FILE* fdata = fopen(datafile, "r");
if (fdata == NULL) {
printf("文件%s打开失败,程序即将退出..", datafile);
exit(-11);
}
int ysize = 0;
while (!feof(fdata)) {
//按着每行14份数据为一组进行分割
for (int i = 0; i < LABELS; i++) {
fscanf(fdata, "%lf", &data[ysize][i]);
}
ysize++;
}
fclose(fdata);
// copy(data, data_slice, 0, 0, TRAIN_SIZE, LABELS);
for (int i = 0; i < TRAIN_SIZE; i++) {
for (int j = 0; j < LABELS; j++) {
train_data[i][j] = data[i][j];
}
}
//for (int i = 0; i < TRAIN_SIZE * LABELS; i++) {
// printf("%lf ", train_data[i / 14][i % 14]);
// if (i % 14 == 0)printf("\n");
//}
for (int i = 0; i < LABELS; i++) {
maximums[i] = getmax_col(train_data, i);
minimums[i] = getmin_col(train_data, i);
avgs[i] = getavg_col(train_data, i);
//printf("%lf %lf %lf\n", maximums[i], minimums[i], avgs[i]);
}
//归一化
for (int x = 0; x < TRAIN_SIZE; x++) {
for (int y = 0; y < DATA_SIZE; y++) {
if (maximums[y] - minimums[y] == 0)continue;
data[x][y] = (data[x][y] - minimums[y]) / (maximums[y] - minimums[y]);
}
}
/*for (int y = 0; y < TRAIN_SIZE; y++) {
printf("%.5lf ", data[y][0]);
}
printf("\n");*/
for (int i = 0; i < TRAIN_SIZE; i++) {
for (int j = 0; j < LABELS; j++) {
train_data[i][j] = data[i][j];
}
}
printf("数据载入完成\n");
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
///////////////////////////////__NETWORK_H__/////////////////////////////////
/// <summary>
/// 初始化
/// </summary>
void __init__() {
init = 1;
printf("***w***\n");
for (int i = 0; i < DATA_SIZE; i++) {
//w[i] = 1.0 * normal_random();
printf("%.2lf ", w[i]);
}
printf("\n");
b = 0.0;
printf("初始化完成\n");
}
/// <summary>
/// 前向计算
/// </summary>
/// <param name="x">数据集,大小为TRAIN_SIZE * DATA_SIZE</param>
/// <param name="z">用于接受返回值的数组,其值为基于当前w b计算得来的预测值</param>
void forward(const double x[TRAIN_SIZE][DATA_SIZE], double z[TRAIN_SIZE]) {
if (!init) {
printf("网络未进行初始化!--forward 错误代码:-1");
exit(-1);
}
for (int i = 0; i < TRAIN_SIZE; i++) {
z[i] = vectordot(x[i], w) + b;
//printf("%lf\n",z[i]);
}
}
/// <summary>
/// 计算损失
/// </summary>
/// <param name="z">当前w b下的预测值[将用于与标签值比较],大小为TRAIN_SIZE</param>
/// <param name="y">标签值,大小为TRAIN_SIZE</param>
/// <returns>一个double,代表预测值与实际值的误差,误差越小,返回值越小</returns>
double loss(double z[TRAIN_SIZE],const double y[TRAIN_SIZE]) {
if (!init) {
printf("网络未进行初始化!--loss 错误代码:-2");
exit(-2);
}
//printf("::vectorsub ");
double error[TRAIN_SIZE];
vectorsub(z, y, error);
/*for (int i = 0; i < TRAIN_SIZE; i++) {
printf("%lf ", z[i]);
}
printf("\n");*/
//printf("::vectormultiply ");
double cost[TRAIN_SIZE];
vectormultiply(error, error, cost);
/*for (int i = 0; i < TRAIN_SIZE; i++) {
printf("%.3lf ", cost[i]);
}
printf("\n***********************************\n");*/
double dcost = getavg(cost, TRAIN_SIZE);
return dcost;
}
/// <summary>
/// 梯度计算
/// </summary>
/// <param name="x">数据集,大小为TRAIN_SIZE * DATA_SIZE</param>
/// <param name="y">标签集,大小为TRAIN_SIZE</param>
/// <returns>返回Pair 第一项为梯度w 第二项为梯度b</returns>
Pair gradient(const double x[TRAIN_SIZE][DATA_SIZE], const double y[TRAIN_SIZE]) {
if (!init) {
printf("网络未进行初始化!--gradient 错误代码:-3");
exit(-3);
}
//printf("gradient::forward\n");
//z : 404 * 1
//y : 404 * 1
//x : 404 * 13
double z[TRAIN_SIZE];
forward(x, z);
/*for (int i = 0; i < TRAIN_SIZE; i++) {
printf("%.3lf ", z[i]);
}
printf("\n");*/
//printf("gradient::sub\n");
double tgradient_b[TRAIN_SIZE];
vectorsub(z, y, tgradient_b);
/*for (int i = 0; i < TRAIN_SIZE; i++) {
printf("%lf %d\n", tgradient_b[i], i);
}*/
//printf("gradient::multiply2\n");
double tgradient_w[TRAIN_SIZE][DATA_SIZE];
for (int i = 0; i < TRAIN_SIZE; i++) {
for (int j = 0; j < DATA_SIZE; j++) {
tgradient_w[i][j] = tgradient_b[i] * x[i][j];
//printf("%.2lf ", tgradient_w[i][j]);
}
//printf("\n");
}
//for (int i = 0; i < TRAIN_SIZE; i++) {
// vectormultiply(tgradient_b, x[i], tgradient_w[i]);
//}
//printf("end multiply\n");
double gradient_w[DATA_SIZE];
//列均值
for (int i = 0; i < DATA_SIZE; i++) {
double sum = 0.0;
for (int x = 0; x < TRAIN_SIZE; x++) {
sum += tgradient_w[x][i];
//printf("::gra%lf %d\n", tgradient_w[x][i], i);
}
gradient_w[i] = sum / (double)TRAIN_SIZE;
}
//printf("end avg\n");
double gradient_b = getavg(tgradient_b, TRAIN_SIZE);
/*for (int i = 0; i < TRAIN_SIZE; i++) {
free(tgradient_w[i]);
}
free(tgradient_w);
free(tgradient_b);
free(z);*/
//printf("%lf\n", gradient_b);
return (Pair) { gradient_w, gradient_b };
}
/// <summary>
/// 更新权重w, b
/// </summary>
/// <param name="gradient_w">线性的回归的斜率</param>
/// <param name="gradient_b">线性回归的坐标轴位移</param>
void update(const double gradient_w[DATA_SIZE], const double gradient_b) {
if (!init) {
printf("网络未进行初始化!--update 错误代码:-4");
exit(-4);
}
for (int i = 0; i < DATA_SIZE; i++) {
w[i] -= learningrate * gradient_w[i];
}
b -= learningrate * gradient_b;
}
/// <summary>
/// 训练主体
/// </summary>
/// <param name="x">数据集,大小为TRAIN_SIZE * DATA_SIZE</param>
/// <param name="y">标签集,大小为TRAIN_SIZE</param>
void train(const double x[TRAIN_SIZE][DATA_SIZE], const double y[TRAIN_SIZE]) {
if (!init) {
printf("网络未进行初始化!--train 错误代码:-5");
exit(-5);
}
printf("开始训练\n");
double L = -1;
for (int i = 0; i < iterations; i++) {
if (i == iterations * 0.3) {
learningrate /= 2;
}
if (i == iterations * 0.5) {
learningrate /= 2;
}
if (i == iterations * 0.8) {
learningrate /= 2;
}
//printf("进行forward \n");
double z[TRAIN_SIZE];
forward(x, z);
//printf("计算loss \n");
L = loss(z, y)/100;
/*for (int i = 0; i < TRAIN_SIZE; i++) {
printf("%lf %lf\n", z[i], y[i]);
}*/
//printf("开始gradient \n");
Pair pair = gradient(x, y);
double* gradient_w = pair.first;
double gradient_b = pair.second;
//printf("进行更新\n");
update(gradient_w, gradient_b);
if ((i + 1) % log_step == 0) {
printf("> iter %d, loss %.10lf lr %lf\n", i, L, learningrate);
}
}
printf("训练完成,共训练轮次:%d轮 最终得到的参数为:\n", iterations);
//printf("************gradient_w************\n");
printgradientw();
for (int i = 0; i < DATA_SIZE; i++) {
printf("\033[36mw[%2d] = %64.60lf\033[m\n", i, w[i]);
}
//printf("\n************gradient_b************:\n");
printgradientb();
printf("\033[36m b = %64.60lf\033[m\n\n", b);
printf("基于该参数的模型预测损失为:%lf\n", L);
printf("正在导出模型...\n");
FILE* fout = fopen("train_finish.luoy", "w");
if (fout == NULL) {
printf("模型导出错误,程序即将退出");
system("pause");
exit(-12);
}
for (int i = 0; i < DATA_SIZE; i++) {
fprintf(fout, "%.60lf ", w[i]);
}
fprintf(fout, "\n");
fprintf(fout, "%.60lf", b);
for (int i = 0; i < LABELS; i++) {
fprintf(fout,"\n%lf %lf %lf", maximums[i], minimums[i], avgs[i]);
}
fclose(fout);
printf("模型导出完成!\n");
printbye(1);
printhello(1);
printf("按任意键退出...\n");
system("pause");
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
///////////////////////////__VECTORCOMPUTATION_H__///////////////////////////
//add, subtract, multiply and divide
/// <summary>
/// 两个DATA_SIZE大小的一纬向量相乘,返回一个两个向量每项乘积之和
/// </summary>
/// <param name="x">向量1</param>
/// <param name="arr">向量2</param>
/// <returns></returns>
double vectordot(const double x[DATA_SIZE], const double arr[DATA_SIZE]) {
double ans = 0;
for (int i = 0; i < DATA_SIZE; i++) {
ans += x[i] * arr[i];
}
return ans;
}
/// <summary>
/// 两个一维向量相减,返回一维向量
/// </summary>
/// <param name="x">减数</param>
/// <param name="y">被减数</param>
/// <param name="ans">用于接收返回值的数组</param>
/// <returns></returns>
void vectorsub(const double x[TRAIN_SIZE], const double y[TRAIN_SIZE], double ans[TRAIN_SIZE]) {
for (int i = 0; i < TRAIN_SIZE; i++) {
ans[i] = x[i] - y[i];
}
}
/// <summary>
/// 两个一维向量相乘
/// </summary>
/// <param name="x">向量1</param>
/// <param name="y">向量2</param>
/// <param name="ans">用于接收返回值的数组</param>
void vectormultiply(const double x[TRAIN_SIZE], const double y[TRAIN_SIZE], double ans[TRAIN_SIZE]) {
for (int i = 0; i < TRAIN_SIZE; i++) {
ans[i] = x[i] * y[i];
}
}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。