nvidia-docker
。nvidia-docker
的安装可以参考其GitHub上的描述,还是非常轻松的。这是Caffe在docker hub上的镜像仓库:nvidia-docker
已经停用了nvidia-docker
这个命令,取而代之的是docker run --gpus
,通过参数--gpus
来指定启用GPU支持和具体连接哪一块GPU,一般后面跟参数all
用来指定连接所有的GPU。device
参数来指定连接某一块具体的GPU:-v
将物理机中的/media/ubuntu/mnist
映射到docker容器中的/workspace
目录下,这样在docker容器中对/workspace
目录的访问就相当于对物理机中/media/ubuntu/mnist
的访问了。这个访问是双向的,我们可以将caffe在docker容器中的训练结果保存到容器的/workspace
目录下,这样我们就可以在物理机中的/media/ubuntu/mnist
拿到相关的结果。同样,我们也可以将相关的测试数据放入物理机中的/media/ubuntu/mnist
目录下,这样我们就可以在容器中指定/workspace
为相关的数据和网络参数路径。TL;DR如果上述的流程在你的电脑上训练模型时出现如下错误的话:1Check failed: error == cudaSuccess (8 vs. 0) invalid device functionCopied!这是由于你的显卡配置错误导致的,这个配置是在$CAFFE_ROOT
下的Makefile.config
里面配置的,重新配置需要重新编译caffe,重新编译以修正此错误可以参考如下文章:如果你在docker里面运行出现了上述的错误,那就不建议你修改Makefile.config
然后重新编译了,这个可以通过换docker镜像直接解决,我们上面所用的docker镜像是bvlc/caffe:gpu
,我们只要换成NVIDIA caffe(NVCaffe)即可:1docker pull nvidia/caffeCopied!P.S.上述镜像可以直接从docker hub中获取,但是已经被标记为弃用(DEPRECATED)了。我们可以从NVIDIA GPU Cloud中下到最新版本,但是因为国内众所周知的网络原因,下面的命令往往不能正常地拉取镜像,需要给docker配置代理才能正常拉取:1docker pull nvcr.io/nvidia/caffe:20.02-py3Copied!
transform_param
用于对输入数据进行一些变换,scale
用于对其中的像素值进行缩放,将其值投射到区间[0, 1)中,其值为 data
一个是label
。data_param
中的batch_size
指的是一次从数据集中读取的数据量的大小。top
用于指定该层的输出,我们由此看到该层的输出有2,其一为data
,也就是数据,其二为label
,也就是其所对应的标签。type
为Convolution
,对于参数lr_mult
意指对基础学习率的系数,也就是实际学习率为在solver
文件里面指定的基础学习率base_lr
乘以这里的lr_mult
。对于当前layer
里面指定的第一个param
其针对训练参数w
,第二个param
其对应训练参数b
,由此我们可以看出,在上述的例子中,当前层对b
的学习率是对w
的学习率的两倍,且对w
的学习率等同于其在solver.prototxt
文件中指定的基础学习率。convolution_param
,其用于指定一些关于卷积核的参数。num_output
为卷积的通道数,换句话说也就是卷积核的个数。kernel_size
为卷积核的大小,在这里指定一个5,意为卷积核的大小为5x5。stride
用于指定卷积核行走时的步长。weight_filler
即为使用何种算法来填充卷积核,在这里指定的是xavier
算法。bias_filler
即为填充b
矩阵的填充方法,在这里指定的为constant
,使用常量(一般为0)填充。TL;DR卷积流程:1# 将输入图片转化为CNN可用的形状2# shape中的第一个-1用于表示输入图片的数量,如同x shape中的None3# 28, 28, 1用于表示这是一个28x28的图片,有1个通道(因为都是黑白的)4x_image = tf.reshape(x, shape=[-1, 28, 28, 1])56# 卷积核的宽度和高度均为4,第一层输入通道数为1,输出通道数为327# 将一张图片分为32个特征8con1_weight = init_weight([4, 4, 1, 32])9con1_bias = init_bias([32])10con1 = tf.nn.relu(conv2d(x_image, con1_weight) + con1_bias)Copied!
bottom
和一个top
,用于指定该层的输入参数和输出参数。其实在我看来,Caffe中的bottom
和top
后面只不过是起到了一个标签的作用,在输入层中我们定义了两个top
,一个是data
一个是label
,data
和label
实则为用于标记数据的标签,然后在卷积层中的bottom
指定为data
,告诉Caffe该层需要获取一个标签值为data
的数据。然后Caffe会自动将带有这个标签的数据作为输入传入该层。type
为Pooling
,使用pooling_param
为其设置相关参数,其内部的pool
参数用于指定池化的方法,在这采用的是最常用的max-pooling,也就是取一个区域内的最大值,如下图所示:kernel_size
用于指定max-pooling的区域大小,在这的设定为2,也就是2x2。stride
用于指定池化的步长为2,这样池化的过程中就不会出现重叠的情况了。这跟上图所示是一样的情况。top
不等于bottom
的话,就会把计算好的输出数据放在一个新建的名为你新指定的名称的数据集中。