线性回归的深度学习神经网络(C++版)

深度学习的基础简单单元就是线性回归,线性回归的背景知识我们都有很多丽了解,最简单的就是一元线性回归,复杂的神经网络就是很多(相当大)的线性单元构成,包括卷积等。为了体现微分的数值计算深入理解深度学习是如何工作的,尽管强大的深度学习框架可以减少大量重复性工作,但若过于依赖它提供的便利,会导致我们很难理解工作原理。因此,这里介绍如何只利用C++来实现一个一元线性回归的训练。

原始数据集

变量12345678910
x i x_{i} xi1.11.31.522.22.933.23.23.7
y i y_{i} yi39343462053773143525398915664260150544456444557189

神经网络的构建

假设

一元线性回归模型 h θ ( x ) = θ 0 + θ 1 x h_{\theta}(x)=\theta_{0}+\theta_{1} x hθ(x)=θ0+θ1x,其中 θ i \theta_{i} θi为参数, h θ ( x ) h_{\theta}(x) hθ(x)表示在 θ \theta θ条件下对应的学习值,也即 θ = [ θ 0 , θ 1 ] \theta=[\theta_{0},\theta_{1}] θ=[θ0,θ1]为学习值。

代价函数

当前参数的对该模型的一个拟合评价,对于线性回归模型很显然它的差向量模值是体现参数好坏的一个标准。

J ( θ 0 , θ 1 ) = 1 2 m ∑ i = 1 m ( h θ ( x ( i ) ) − y ( i ) ) 2 J\left(\theta_{0}, \theta_{1}\right)=\frac{1}{2 m} \sum_{i=1}^{m}\left(h_{\theta}\left(x^{(i)}\right)-y^{(i)}\right)^{2} J(θ0,θ1)=2m1i=1m(hθ(x(i))y(i))2

梯度下降优化算法

θ j : = θ j − α ∂ ∂ θ j J ( θ 0 , θ 1 ) \theta_{j}:=\theta_{j}-\alpha \frac{\partial}{\partial \theta_{j}} J\left(\theta_{0}, \theta_{1}\right) θj:=θjαθjJ(θ0,θ1)

梯度下降法来源于牛顿迭代算法,牛顿迭代算法就是找最低点通过梯度去计算,对已有的自变量进行微调,这里的 α \alpha α是指牛顿下降法更新的幅度,也就是在机器学习中的学习率,他的高低影响了深度学习学习的效果和城西运行的时间。

C++源代码

gitee下载地址
Net.h模型头文件

#pragma once

#include <iostream>
#include <vector>
#include<random>
#include <iomanip>
#include<string>
using namespace std;
class Net
{
private:
	vector<double> X;//预存特征数据
	vector<double> Y;//预存标签数据
	vector<double> Y_;//预测标签值
	vector<double> L;//每项的损失
	double loss;//总损失
	double W[2];//权向量,模型中训练的参数值
	double gW[2];//梯度下降法值,保存模型中训梯度
	double lr;//学习率
	int train_epochs;//学习代数
    /**以下为C++表格和进度条绘制简单代码**/
	bool process;
	void drawLine(vector<int> max, int columns);
	void drawLine(int max, int columns);
	void drawDatas(vector<int> max, vector<vector<double>> Str, vector<string> D, int columns, int row);
	void drawDatas(int max, vector<vector<double>> Str, vector<string> D, int columns, int row);
	void show(int epochs);
    /**以上为C++表格和进度条绘制简单代码**/
public:
	Net(double x[], double y[], int num,double lr,int train_epochs);//构造函数
	void model();//训练函数
	void predict();//预测函数
	void calLoss();//损失函数
	void grad();//计算梯度函数
	void output();//输出函数
    /**以下为C++表格和进度条绘制简单代码**/
	void setProcess(bool process);
    /**以上为C++表格和进度条绘制简单代码**/
};


Net.cpp

#include "Net.h"
/**
x:输入特征
y:标签
num:数据集大小
lr:学习率
train_epochs:训练代数
**/
Net::Net(double x[], double y[], int num,double lr,int train_epochs)
{
    /*进行数据填充操作**/
	for (int i = 0; i < num; i++)
	{
		this->X.push_back(x[i]);
		this->Y.push_back(y[i]);
	}
	this->lr = lr;
	this->train_epochs = train_epochs;
	this->process = false;
}

void Net::model()
{
    default_random_engine dre(0);//设置随机种子
	uniform_real_distribution<double> rand_real(-1.0, 1.0);
	W[0] = rand_real(dre);//类似于python深度学习库中学习参数预先赋值
	W[1] = rand_real(dre);
	int epochs = 0;
	while (epochs++< this->train_epochs)//迭代
	{
		this->predict();//计算预测
		this->calLoss();//计算损失
		show(epochs);
		this->grad();//计算梯度
		this->W[0] = this->W[0] - this->lr*this->gW[0];//计算梯度下降法
		this->W[1] = this->W[1] - this->lr*this->gW[1];//计算梯度下降法
	}
	predict();//最终预测
	calLoss();//最终顺式
	cout << "****************" << endl;
}

void Net::predict()
{
	Y_.clear();//对已有的预测清零
	for (int i = 0; i < X.size(); i++)
	{
		Y_.push_back( W[0] + W[1] * X[i]);//预测
	}
}

void Net::calLoss()
{
	L.clear();//对已有的单损失清零
	this->loss = 0;//对已有的总损失清零
	for (int i = 0; i < X.size(); i++)
	{
		L.push_back((Y_[i]- Y[i])*(Y_[i] - Y[i]));//计算单损失
		this->loss += L[i];
	}
	this->loss /= (2 * L.size());//计算总损失
}

void Net::grad()
{
	double deltax = 0.00001;//数值梯度deltax趋于0
	double deltay = 0;
	vector<double> temp(X.size());//数值梯度每项损失
	for (int i = 0; i < X.size(); i++)
	{
		temp[i] = W[0]+ deltax + W[1] * X[i];
		deltay += (temp[i] - Y[i])*(temp[i] - Y[i]);
	}
	deltay /= (2 * X.size());//数值梯度总损失当数值梯度deltax趋于0
	gW[0] = (deltay- this->loss )/ deltax;
    //下面同理
	deltay = 0;
	for (int i = 0; i < X.size(); i++)
	{
		temp[i] = W[0]  + (W[1] + deltax )* X[i];
		deltay += (temp[i] - Y[i])*(temp[i] - Y[i]);
	}
	deltay /= (2 * X.size());
	gW[1] = (deltay - this->loss) / deltax;
}

void Net::output()
{
	vector<string> D;
	D.push_back("W[0]");
	D.push_back("W[1]");
	D.push_back("loss");
	vector<double> row;
	row.push_back(this->W[0]);
	row.push_back(this->W[1]);
	row.push_back(this->loss);
	vector<vector<double>> data;
	data.push_back(row);
	int max = 9;
	this->drawDatas(max, data, D, D.size(), data.size());
	///
	D.clear();
	D.push_back("X");
	D.push_back("Y");
	D.push_back("Y_");
	D.push_back("L");
	data.clear();
	for (int i = 0; i < X.size(); i++)
	{
		row.clear();
		row.push_back(X[i]);
		row.push_back(Y[i]);
		row.push_back(Y_[i]);
		row.push_back(L[i]);//		cout << X[i]<<"    " << Y[i] << "    " << Y_[i] << "    " << L[i] << endl;
		data.push_back(row);
	}
	this->drawDatas(max, data, D, D.size(), data.size());

}
 /**以下为C++表格和进度条绘制简单代码**/
void Net::setProcess(bool process)
{
	this->process = process;
}
void Net::drawLine(vector<int> max, int columns) {  //画行线
	for (int i = 0; i < columns; i++) {
		cout << "+-";
		for (int j = 0; j <= max[i]; j++) {
			cout << '-';
		}
	}
	cout << '+' << endl;
}
void Net::drawLine(int max, int columns) {  //画行线
	for (int i = 0; i < columns; i++) {
		cout << "+-";
		for (int j = 0; j <= max; j++) {
			cout << '-';
		}
	}
	cout << '+' << endl;
}
void Net::drawDatas(vector<int> max, vector<vector<double>> Str, vector<string> D, int columns, int row) {
	drawLine(max, columns);
	for (int i = 0; i < D.size(); i++) {
		cout << "| " << setw(max[i]) << setiosflags(ios::left) << setfill(' ')<< D[i] << ' ';
	}
	cout << '|' << endl;
	drawLine(max, columns);
	for (int i = 0; i < row; i++) {
		for (int j = 0; j < columns; j++) {
			cout << "| " << setw(max[j]) << setiosflags(ios::left) << setfill(' ');
			cout << Str[i][j] << ' ';
		}
		cout << '|' << endl;
	}
	drawLine(max, columns);
}
void Net::drawDatas(int max, vector<vector<double>> data, vector<string> header, int columns, int row) { 
	drawLine(max, columns);
	for (int i = 0; i < header.size(); i++) {
		cout << "| " << setw(max) << setiosflags(ios::left) << setfill(' ') << header[i] << ' ';
	}
	cout << '|' << endl;
	drawLine(max, columns);
	for (int i = 0; i < row; i++) {
		for (int j = 0; j < columns; j++) {
			cout << "| " << setw(max) << setiosflags(ios::left) << setfill(' ');
			cout << data[i][j] << ' ';
		}
		cout << '|' << endl;
	}
	drawLine(max, columns);
}

void Net::show(int epochs)
{
	if (process)
	{
		cout << "第" << epochs << "代:" << loss << endl;
	}
	else
	{ 
		cout.width(3);//i的输出为3位宽  
		cout << 100*epochs/ this->train_epochs << "%";
		cout << "\b\b\b\b";//回删三个字符,使数字在原地变化  
	}
}
 /**以上为C++表格和进度条绘制简单代码**/
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值