【例9.3】以Kaggle上的手写数字数据集(MNIST)竞赛为例子,通过mxnet定义卷积神经网络,并在GPU上快速训练模型。
(1)数据准备
从Kaggle上下载数据,并将它们放入“data/”文件夹中。然后读入数据,并做一些预处理工作。
>require(mxnet)
>train<-read.csv′(data/train.csv′,header=TRUE)
>test<-read.csv′(data/test.csv′,header=TRUE)
>train<-data.matrix(train)
>test<-data.matrix(test)
>train.x<-train[,-1]
>train.y<-train[,1]
>train.x<-t(train.x/255)
>test<-t(test/255)
最后两行预处理的作用有两个:
1)原始灰度图片数值处在[0,255]之间,将其变换到[0,1]之间。
2)mxnet接受像素X图片的输入格式,所以对输入矩阵进行了转置。
(2)建模
LeNet神经网络结构是由Yann LeCun提出的,并用于识别手写数字,也是最早的卷积神经网络之一。同样地,这里使用Symbol语法来定义,不过这个结构会比较复杂。
>data<-mx.symbol.Variable′(data′)
#第一个卷积
>conv1<-mx.symbol.Convolution(data=data,kernel=c(5,5),num_filter=20)
>tanh1<-mx.symbol.Activation(data=conv1,act_type="tanh")
>pool1<-mx.symbol.Pooling(data=tanh1,pool_type="max",
kernel=c(2,2),stride=c(2,2))
#第二个卷积
>conv2<-mx.symbol.Convolution(data=pool1,kernel=c(5,5),
num_filter=50)
>tanh2<-mx.symbol.Activation(data=conv2,act_type="tanh")
>pool2<-mx.symbol.Pooling(data=tanh2,pool_type="max",
kernel=c(2,2),stride=c(2,2))
#第一个全连接
>flatten<-mx.symbol.Flatten(data=pool2)
>fc1<-mx.symbol.FullyConnected(data=flatten,num_hidden=500)
>tanh3<-mx.symbol.Activation(data=fc1,act_type="tanh")
#第二个全连接
>fc2<-mx.symbol.FullyConnected(data=tanh3,num_hidden=10)
>lenet<-mx.symbol.SoftmaxOutput(data=fc2) #损失函数
为了让输入数据的格式能对应LeNet,需要将数据变成R中的array格式。
>train.array<-train.x
>dim(train.array)<-c(28,28,1,ncol(train.x))
>test.array<-test
>dim(test.array)<-c(28,28,1,ncol(test))
接下来,分别使用CPU和GPU来训练这个模型,从而展现不同的训练效率。
>n.gpu<-1
>device.cpu<-mx.cpu()
>device.gpu<-lapply(0:(n.gpu-1),function(i){mx.gpu(i)})
将GPU的每个核以list的格式传递进去,如果有BLAS等自带矩阵运算并行的库存在,则没必要对CPU这么做了。
先在CPU上进行训练,只进行一次迭代。
>mx.set.seed(0)
>tic<-proc.time()
>model<-mx.model.FeedForward.create(lenet,
X=train.array,
y=train.y,
ctx=device.cpu,
num.round=1,
array.batch.size=100,
learning.rate=0.05,
momentum=0.9,
wd=0.00001,
eval.metric=mx.metric.accuracy,
epoch.end.callback=mx.callback.log.train.metric(100))(www.xing528.com)
Starttrainingwith1devices
Batch[100]Train-accuracy=0.1066
Batch[200]Train-accuracy=0.16495
Batch[300]Train-accuracy=0.401766666666667
Batch[400]Train-accuracy=0.537675
[1]Train-accuracy=0.557136038186157
print(proc.time()-tic)
user system elapsed
130.030204.97683.821
在CPU上训练一次迭代一共花了83 s。接下来在GPU上训练5次迭代:
mx.set.seed(0)
tic<-proc.time()
model<-mx.model.FeedForward.create(lenet,
X=train.array,
y=train.y,
ctx=device.gpu,
num.round=5,
array.batch.size=100,
learning.rate=0.05,
momentum=0.9,
wd=0.00001,
eval.metric=mx.metric.accuracy,
epoch.end.callback=mx.callback.log.train.metric(100))
Start training with 1 devices
Batch[100]Train-accuracy=0.1066
Batch[200]Train-accuracy=0.1596
Batch[300]Train-accuracy=0.3983
Batch[400]Train-accuracy=0.533975
[1]Train-accuracy=0.553532219570405
Batch[100]Train-accuracy=0.958
Batch[200]Train-accuracy=0.96155
Batch[300]Train-accuracy=0.966100000000001
Batch[400]Train-accuracy=0.968550000000003
[2]Train-accuracy=0.969071428571432
Batch[100]Train-accuracy=0.977
Batch[200]Train-accuracy=0.97715
Batch[300]Train-accuracy=0.979566666666668
Batch[400]Train-accuracy=0.980900000000003
[3]Train-accuracy=0.981309523809527
Batch[100]Train-accuracy=0.9853
Batch[200]Train-accuracy=0.985899999999999
Batch[300]Train-accuracy=0.986966666666668
Batch[400]Train-accuracy=0.988150000000002
[4]Train-accuracy=0.988452380952384
Batch[100]Train-accuracy=0.990199999999999
Batch[200]Train-accuracy=0.98995
Batch[300]Train-accuracy=0.990600000000001
Batch[400]Train-accuracy=0.991325000000002
[5]Train-accuracy=0.991523809523812
>print(proc.time()-tic)
user system elapsed
9.2881.6806.889
在GPU上训练5轮迭代只花了不到7 s,快了数十倍!可以看出,对于这样的网络结构,GPU的加速效果是非常显著的。有了快速训练的办法,可以很快地做预测,并且提交到Kaggle上。
>preds<-predict(model,test.array)
>pred.label<-max.col(t(preds))-1
>submission<-data.frame(ImageId=1:ncol(test),Label=pred.label)
>write.csv(submission,file=′submission.csv′,row.names=FALSE,
quote=FALSE)
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。