本教程参考《RDeepLearningEssential》
这一篇我们通过实践来进行神经网络的学习,预测和分类等
2.1 R语言神经网络-nnet
我们先进行浅层神经网络的学习,使用nnet包和RSNNS包,我们通过caret包来调用nnet包。caret包是‘Classification and Regression Training’的缩写。我们第一个例子也是基本所有深度学习都会进行的第一个例子:手写字体识别。
2.1.1神经网络构建(多层感知器模型)-最简单尝试
我们从kaggle中读取数据:Digit Recognizer | Kaggle
数据包括训练数据和测试数据,这是是标准的数据形式,因为就像我们上学的时候平时做练习感觉自己学会了,这么检验呢,就是去考试检验一下,这个考试的卷子就是测试数据。
dig_train <- read.csv("C:\\Users\\Huzhuocheng\\Desktop\\digit-recognizer\\train.csv")
dim(dig_train) #数据维度查看
head(colnames((dig_train), 5)) #查看前五个列名
tail(colnames((dig_train),5)) #查看后五个列名
head(dig_train[, 1:5])
我们可以理解第一列是我们方程的Y,也就是靶,而后面的几列是我们的x,有700多个x,解方程用手解应该是不太显示,所以我们才有机器学习和深度学习,因为方程用手解可能解不出确切值,这个我们叫没有数值解,但是计算机可能解出来近似解,这个解可以通过算法优化得到最优解,一句话:人工智能得出的是最接近的答案!
第二步,我们要把标签(第一列)转换为因子,这样它就不会作为纯粹的Y的数值,你懂数字1和‘数字1’的区别,就能理解这个操作,并且我们选择其中的6000个数据进行练习。我们再检查一下数据的真实分布(也就是正确的Y的分布)
dig_train$label <- factor(dig_train$label, levels = 0:9)
i <- 1:6000
dig_X <- dig_train[i, -1]
dig_Y <- dig_train[i, 1]
barplot(table(dig_Y))
接下来我们正式开始使用神经网络:
这里我们设置隐藏层为5的神经网络,并且设置正则化值为0.1(也就是惩罚值,这个我觉得我在以后出的机器学习教程里会更详细的论述,你可以先理解为防止训练过拟合,也就是只会刷题不会考试了)我们训练完可以看一下我们预测的分布:
在神经网络的训练中,maxit参数控制了反向传播算法的最大迭代次数。将其设置为100次迭代,主要是为了在模型训练的过程中提供一个停止条件,以确保模型能够在合理的计算时间内完成训练。反向传播算法是神经网络的核心学习规则之一,它通过计算损失函数关于模型参数的梯度,然后根据一定的优化策略(如梯度下降)来更新模型参数,以期最小化损失函数。在这个过程中,迭代次数起到了至关重要的作用。
迭代次数决定了模型训练的深度。理论上,如果迭代次数足够多,模型能够更精细地调整其参数以适应训练数据。但是,随着迭代次数的增加,模型训练的时间也会相应增长,而且在某些情况下,过多的迭代次数可能会导致模型在训练数据上过拟合,反而降低了模型在新数据上的泛化能力。
library('caret')
set.seed(1234)
dig_m1 <- train(x = dig_X, y = dig_Y,
method = 'nnet',
tuneGrid = expand.grid(
.size = c(5),
.decay = 0.1),
trControl = trainControl(method = "none"),
MaxNWts = 10000,
maxit = 100
)
dig_Yhat1 <- predict(dig_m1) #预测值
barplot(table(dig_Yhat1))
预测出来是一坨,因为我特意将一些参数改的比较小,这个不是一个非常好的神经网络。
2.1.2 模型训练预测的评价
我们不能总是通过可视化分布来看模型的效果,而是应该通过数学指标,我们通过阳性预测和阴性预测来实现对于灵敏度和特异度的计算:
比如数字‘1’的灵敏度如果为80%,则表示80%的0被正确预测,而如果数字‘1’的特异度为75%,则表示75%的被预测为非数字‘1’的数字不是数字‘1’,当然我觉得特异度是更为重要的指标,因为认错人比没认出来更为严重,我们使用R语言计算一下这些指标:
cm <- caret::confusionMatrix(xtabs(~dig_Yhat1 + dig_Y))
# 可视化混淆矩阵
plot(cm$table, main = "Confusion Matrix", col = cm$byClass, las = 1)
通过这个结果我们可以看到每个数字的识别情况,主要是关注前两个,也就是灵敏度和特异度
2.1.3 模型优化
我们增加网络的节点数目和最大权重来进行第一次优化,你会发现你的运行速度明显变慢了
#第一次优化
set.seed(1234)
dig_m2 <- train(x = dig_X, y = dig_Y,
method = 'nnet',
tuneGrid = expand.grid(
.size = c(10),
.decay = 0.1),
trControl = trainControl(method = "none"),
MaxNWts = 50000,
maxit = 100
)
dig_Yhat2 <- predict(dig_m2) #预测值
barplot(table(dig_Yhat2))
cm2 <- caret::confusionMatrix(xtabs(~dig_Yhat2 + dig_Y))
这次我们的分布和各种参数有了明显的好转,不过说实话总体的准确率没有超过70%,相当于还是在抛硬币,是不可以被接受的。我们进行下一次优化:
#第二次优化
set.seed(1234)
dig_m3 <- train(x = dig_X, y = dig_Y,
method = 'nnet',
tuneGrid = expand.grid(
.size = c(45),
.decay = 0.1),
trControl = trainControl(method = "none"),
MaxNWts = 50000,
maxit = 100
)
dig_Yhat3 <- predict(dig_m3) #预测值
barplot(table(dig_Yhat3))
cm3 <- caret::confusionMatrix(xtabs(~dig_Yhat3 + dig_Y))
cm3
经过漫长的等待,我们的预测结果已经非常好了,整体的预测率到达了0.86!当然如果还需要更好的结果可以进一步优化节点及惩罚值的大小。
2.2R语言神经网络-SNNS
我们使用斯图加特神经网络仿真器(Stuttgart Neural Network Simulator)来进行训练,它的有点在于更加灵活且可以训练更多神经网络架构,包括循环神经网络及更广泛的学习函数。
install.packages('RSNNS')
library("RSNNS")
head(decodeClassLabels(dig_Y))
set.seed(1234)
dig_m4 <- mlp(as.matrix(dig_X),
decodeClassLabels(dig_Y),
size = 40,
learnFunc = 'Rprop',
shufflePatterns = F,
maxit = 60)
dig_Yhat4 <- fitted.values(dig_m4)
dig_Yhat4 <- encodeClassLabels(dig_Yhat4)
barplot(table(dig_Yhat4))
caret::confusionMatrix(xtabs(~ I(dig_Yhat4 - 1) + dig_Y))
预测效果也不错的0.86。
2.3 生成预测
我们对于分类的可能性不可能同等地位去审视,就像体检,说有30%可能性近视和有30%概率患癌症,这完全是不一样的。我们可以给一个阈值,我们可以展示一下样本内数据的原始概率及对预测值的影响:
dig_Yhat4_insample <- fitted.values(dig_m4)
head(round(dig_Yhat4_insample, 2))
table(encodeClassLabels(dig_Yhat4_insample,
method = "WTA", h = .5))
(1)method = "WTA": 这里指定了编码类别标签的方法为"WTA",即Winner-Takes-All。这是一种常见的策略,用于解决多标签分类问题,其中一个实例可以同时属于多个类别。在这种方法中,只有得分最高的类别会被选中作为该实例的标签。
(2)h = .5: 这个参数可能控制着WTA方法的某种阈值或者决策边界。h可被用来确定何时一个类别足够强以至于被认为是“赢家”。数值.5表示比如当某个类别的预测概率超过0.5时,它就被认为是获胜者。
我们可以使用predict()来生成预测值。
i2 <- 5001:10000
dig_yha4_pred <- predict(dig_m4,
as.matrix(dig_train[i2, -1])
)
table(encodeClassLabels(dig_yha4_pred,
method = 'WTA', h=0))
2.4浅浅分析结果-过拟合问题
过拟合是什么呢,就是一个人他平时学习学的太猛了,习题做的太会了,导致考试反而不会了。
我们的样本内准确度87%,之前拟合的是83%,所以我们过拟合了4%。
caret::confusionMatrix(xtabs(~dig_train[i2, 1] +
I(encodeClassLabels(dig_yha4_pred) -1)))
2.5小结
通过这次的学习,你应该已经能自己使用神经网络进行浅层预测了,我们下次使用一个例子来更深入的理解神经网络。