Torch笔记(三) 一元线性回归
torch中神经网络包官网https://github.com/torch/nn
先简单说说最简单的线性回归,也就是一元线性回归,即只有一个自变量,一个因变量,用式子表示就是Y=aX+b。X表示输入,Y是输出。就是在已知输入X的情况下拟合输出Y。
现在给出一个实例,咱们从例子中玩Torch。这里有一个家庭消费支出(Y)和可支配收入(X)的一个实例,当然,这个数据可能是很久很久以前的,数据如下
X 800 1100 1400 1700 2000 2300 2600 2900 3200 3500 Y 594 638 1122 1155 1408 1595 1969 2078 2585 2530 这个数据是很适合做线性回归分析的,其散点图如下
那如何应用Torch中的神经网络来做这件事呢,首先用包含基本的库
require 'torch'
require 'nn'
torch当然是需要包含的,咱就是在torch中玩嘛,还用到了神经网络,需要包含nn
然后将训练数据塞到程序中去,Torch中唯一的数据结构就是Tensor,当然是把数据放到Tensor中啦,Lua中的重要数据结构是table,这里需要Lua中的table和Torch中的Tensor互相能够转换
table转Tensor,直接将table放到Tensor的构造函数中就行了,Tensor转table需要totable函数
t = {3,5,1}
x = torch.Tensor(t) -- table转成Tensor
y = x:totable() -- Tensor转成table
现在将输入数据和输出数据装进Tensor
local x = torch.Tensor({800,1100,1400,1700,2000,2300,2600,2900,3200,3500})
local y = torch.Tensor({594,638,1122,1155,1408,1595,1969,2078,2585,2530})
因为是线性回归,也就是说,只是简单的输入输出两层神经网络,这里就用的是线性连接Linear,在torch中还有针对稀疏输入的SparseLinear,还有只是用部分网络连接的PartialLinear ,还有比较新的Dropout 。用最简单的网络模型Linear搭建网络如下
local inputDimension = 1
local outputDimensionmo = 1
local mlp = nn.Linear(inputDimension , outputDimensionmo) --建立有1个输入,1个输出的线性回归模型
模型搭建完毕,当然还需要模型的评价标准,不然怎么知道模型对数据拟合的好不好呢,因为是回归,这里就用MSECriterion来处理,当然还有针对多分类的ClassNLLCriterion,还有CrossEntropyCriterion,还有AbsCriterion等等很多。
local criterion = nn.MSECriterion() -- 定义评价标准(损失函数)
下面开始训练过程了,在训练之前,输入格式有待处理一下,刚才输入X和输入Y已经是Tensor了,但是它们都是一维的Tensor。其实当前是有10个样本数据的,每个样本只有一维特征,对应一个数值,也就是说输入其实是10*1的二维矩阵,每个样本的输出也是一维的,10个样本,输出也是10*1的二维矩阵。
local x = torch.Tensor({{800},{1100},{1400},{1700},{2000},{2300},{2600},{2900},{3200},{3500}})
local y = torch.Tensor({{594},{638},{1122},{1155},{1408},{1595},{1969},{2078},{2585},{2530}})
-- 或者直接适用Tensor自带的转换函数reshape
local x = x:reshape(10,1) -- 二维,第一维维度为10,第二维维度为1
local y = y:reshape(10,1)
在正式训练之前,需要对数据进行归一化处理,因为这些数值变化太大了,很容易在迭代的过程中将模型跑偏,从而得不到正确的结果对于连续的数据,在神经网络训练之前数据归一化是个传统的做法,保证神经网络能够学到输入数据的分布。
mean = x[{}]:mean() -- 求出均值,减掉,然后除以标准差
x:add(-mean)
stdv = x[{}]:std()
x:div(stdv)
y_mean = y[{}]:mean()
y:add(-y_mean)
y_stdv = y[{}]:std()
y:div(y_stdv)
然后是训练函数,每一轮训练过程单独抽出来
function gradUpdate(mlp, x, y, criterion, learningRate)
local pred = mlp:forward(x) -- model正向传播
local err = criterion:forward(pred, y) -- criterion正向传播
print(err)
local gradCriterion = criterion:backward(pred, y) -- criterion反向传播
mlp:zeroGradParameters() -- 梯度参数清零
mlp:backward(x, gradCriterion) -- model反向传播
mlp:updateParameters(learningRate)
end
简单解释一下上述函数到底在干嘛,首先是mlp:forward(x)将输入x即可支配收入前向传播计算出的家庭消费支出预测值pred,然后criterion:forward(pred, y)计算家庭消费支出预测值和真实值的误差err,这都是在网络中从前往后算的。然后梯度清零,不清零的话每次会累加,这里用不上累加的梯度,因此清零。然后criterion:backward(pred, y)根据误差反向求损失函数对可支配收入的偏导,然后mlp:backward(x, gradCriterion)通过家庭消费支出的偏导求各个参数(本例中是a、b)的偏导,最后将参数更新。 训练过程如下
for i = 1, 500 do -- 迭代500次
gradUpdate(model, x, y, criterion, 0.01)
end
训练完毕,咱们可以用训练好的模型进行预测了,比方说我想预测可支配收入为3000时的家庭消费支出
local x = torch.Tensor({{3000}})
x:add(-mean) -- 输入数据归一化
x:div(stdv)
local pred = model:forward(x)
pred = pred * y_stdv + y_mean -- 输出数据还原
print(pred)
ok,完整的代码放上来
require 'torch'
require 'nn'
local x = torch.Tensor({{800},{1100},{1400},{1700},{2000},{2300},{2600},{2900},{3200},{3500}})
local y = torch.Tensor({{594},{638},{1122},{1155},{1408},{1595},{1969},{2078},{2585},{2530}})
local inputDimension = 1
local outputDimensionmo = 1
local model = nn.Linear(inputDimension , outputDimensionmo)
local criterion = nn.MSECriterion()
function gradUpdate(mlp, x, y, criterion, learningRate)
local w,dw = mlp:getParameters() -- 这里查看模型的参数w(本例中是权重a、b)dw是损失函数对各权重的偏导
print(w,dw)
local pred = mlp:forward(x)
local err = criterion:forward(pred, y)
print(err)
local gradCriterion = criterion:backward(pred, y)
mlp:zeroGradParameters()
mlp:backward(x, gradCriterion)
mlp:updateParameters(learningRate)
end
mean = x[{}]:mean()
x:add(-mean)
stdv = x[{}]:std()
x:div(stdv)
y_mean = y[{}]:mean()
y:add(-y_mean)
y_stdv = y[{}]:std()
y:div(y_stdv)
for i = 1, 500 do
gradUpdate(model, x, y, criterion, 0.01)
end
local x = torch.Tensor({{3000}})
x:add(-mean)
x:div(stdv)
local pred = model:forward(x)
pred = pred * y_stdv + y_mean
print(pred)