今天刚看到的,简单说一些第一印象(以目前的github repo为准)。整体的设计感觉和Caffe心有灵犀,同时解决了Caffe早期设计当中的一些问题(比如说default stream)。
1. 很高质量的GPU代码
2. 非常好的RNN设计
3. 设计很干净,没有太多的abstraction,这一点比TensorFlow好很多。
4. 高速RDMA的部分貌似没有开源(可能是因为RDMA对于cluster design有一定要求):
5. 设计思路比较像第一代的DL框架,不过考虑到paddle已经有年头了,这样设计还是有历史原因的。
5.1 config是hard-code的protobuf message,这对扩展性可能会有影响。
5.2 可以看到很多有意思的类似历史遗留的设计:采用了STREAM_DEFAULT macro,然后通过TLS的方式定向到非default stream: (所以Paddle off-the-shelf不支持mac?)
5.3 在梯度计算上采用了传统的粗粒度forward/backward设计(类似Caffe)。可能有人会说“所以paddle没有auto gradient generation”,这是不对的,autograd的存在与否和op的粒度粗细无关。事实上,TensorFlow在意识到细粒度operator超级慢的速度以后,也在逐渐转回粗粒度的operator上。
目前只看到这里。总之是一个非常solid的框架,百度的开发功底还是不错的。
安装
关于paddle的安装官方提供了两种方法:
由于安装并没有遇到困难,所以就不在此详述,参考官方进行安装即可。
我们可以从官方下载,进行paddle的hello world实验。
需要强调的是paddle源码更新升级比较快,极有可能出现源码与此讲解或者官方文档冲突的情况。甚至自己的源码demo都会因为其他部门的变化而变得不可执行。这点需要注意
首先从方法论的角度结合(此问题等同于情感标注问题,根据评论者的态度分为正样本和负样本,即二分类问题)来看paddle的处理流程。任何一个paddle的处理流程都包括如下5个基础部分。
1.数据格式准备:
- 获得要处理的样本格式。在Amazon评论数据中,格式为类别标签+Table间隔+评论内容,每一行为一条内容。
2.数据向模型传送:
- 根据需要建立的网络模型,讲数据格式转化为模型能够识别的数据格式,主要是利用PyDataProvider。
3.网络结构:
- paddle的网络结构以layer(如果不明白layer的含义请先学习神经网络和deep learning的基本内容)为基本单位,当然paddle还提供了由常见的由基本layer组合的network(如常见的CNN网络的基本结构:Input => conv => pooling)
- 针对Amazon数据我们简单建立四种模型来训练:逻辑回归模型,词向量模型,卷积模型,时序模型。
- 优化算法,具体的可以不用了解那么多。但是请一定理解BP(反向传导)和sgd(随机梯度下降发)算法。
4.训练模型:
- 当建立网络模型后,只需简单的命令行就可以进行模型的训练。
5.预测
- 当模型训练完毕后,即可读入训练好的模型进行测试或者预测。
数据格式准备
打开paddle的源码,进入/demo/quick_start 目录。创建get_data.sh,并执行。获取已经处理好的数据‘
#!/bin/sh
wget http:
tar -xf amazon.tar
rm -rf amazon.tar
- 下载完毕后,amazon下面的文件主要包括:
- dict.txt:单词编码字典
- elec-100k-train-z.txt:训练的标注样本
- elec-test-z.txt: 测试的标注样本
- test.list:保存测试样本列表,本例为elec-test-z.txt的路径
- train.list:保存训练样本列表,本例为elec-100k-train-z.txt的路径
- 由于旧数据和新更代码的不一致,我们需要将下载好的/demo/quick_start/amazon目录中的文件全部拷贝到/demo/quick_start/data中。
- 并修改/demo/quick_start/data目录下的train.list以及test.list文件。
- 将train.list中的./amazon/elec-100k-train-z.txt改为./data/elec-100k-train-z.txt;将test.list中的./amazon/elec-test-z.txt改为./data/elec-test-z.txt。
数据向模型传送
传送数据的主要代码在/demo/quick_start的dataprovider.py中,代码利用了Python的@(装饰者模式)方法。代码如下:
import os
import sys
from paddle.trainer.PyDataProviderWrapper import *
UNK_IDX = 0
@init_hook_wrapper
def hook(obj, dictionary, **kwargs):
obj.word_dict = dictionary
obj.slots = [SparseNonValueSlot(len(obj.word_dict)), IndexSlot(2)]
@provider(init_hook=hook)
def process_bow(obj, file_name):
with open(file_name, 'r') as fdata:
for line in fdata:
label, comment = line.strip().split('\t')
words = comment.split()
word_slot = [obj.word_dict.get(w, UNK_IDX) for w in words]
yield word_slot, int(label)
@init_hook_wrapper
def hook2(obj, dictionary, **kwargs):
obj.word_dict = dictionary
obj.slots = [IndexSlot(len(obj.word_dict)), IndexSlot(2)]
@provider(use_seq=True, init_hook=hook2)
def process(obj, file_name):
with open(file_name, 'r') as fdata:
for line in fdata:
label, comment = line.strip().split('\t')
words = comment.split()
word_slot = [obj.word_dict.get(w, UNK_IDX) for w in words]
yield word_slot, [int(label)]
@init_hook_wrapper
def hook3(obj, dictionary, **kwargs):
obj.word_dict = dictionary
obj.slots = [IndexSlot(len(obj.word_dict))]
@provider(use_seq=True, init_hook=hook3)
def process_pre(obj, file_name):
with open(file_name, 'r') as fdata:
for line in fdata:
comment = line.strip()
word_slot = [obj.word_dict.get(w, UNK_IDX) for w in comment]
yield word_slot
- provider是PyDataProvider的装饰者,我们需要创建此类实例提供数据。
- init_hook是在PyDataProvider实例创建时的回调函数
- 我们只需要提供数据的slot格式,以及在定义的实例中yield对应的数据
- 最后的process_pre是用来处理预测的样本,没有产生标签数据。
- 关于slot的格式的学习有点复杂,具体请参考:
- 在含有embedding layer的网络中,slot的类型必须为indexSlot类型。 在模型配置中利用define_py_data_sources加载数据:
from paddle.trainer_config_helpers import *
dict_file = "./data/dict.txt"
word_dict = dict()
with open(dict_file, 'r') as f:
for i, line in enumerate(f):
w = line.strip().split()[0]
word_dict[w] = i
define_py_data_sources('data/train.list',
'data/test.list',
module="dataprovider",
obj="process_bow",
args={ "dictionary": word_dict},
train_async=True)
- module:定义数据处理Python文件名。
- obj:指定生成数据的函数。
- args:指定词典。
- train_async:设置异步读取数据。
网络结构
- 四种网络结构的构建分别在四个文件夹:
- trainer_config.cnn.py 卷积模型
- trainer_config.emb.py 词向量模型
- trainer_config.lr.py 逻辑回归模型
- trainer_config.lstm.py 时序模型
- 以词向量模型为例说明构建模型的过程:
data = data_layer(name="word", size=len(word_dict))
label = data_layer(name="label", size=2)
embedding = embedding_layer(input=data, size=128)
avg = pooling_layer(input=embedding, pooling_type=AvgPooling())
output = fc_layer(input=avg, size=2, act=SoftmaxActivation())
cls = classification_cost(input=output, label=label)
- 起始的data_layer层只需要传递名称和尾数即可构建
- 中间层的layer需要传入input参数(此层的输入层)和激活函数等其他参数。这样整个链接的网络就可以建立起来。
关于在代码中优化算法和其他参数的设置可以在setting中实现:
settings(
batch_size=128,
learning_rate=2e-3,
learning_method=AdamOptimizer(),
regularization=L2Regularization(8e-4),
gradient_clipping_threshold=25
)
- 关于Adam优化算法和学习速率以及正则化项等的含义,请大家自行学习deep learning的基础知识。
训练模型
训练脚本:训练的命令行脚本保存在了run.sh文件中。如下:
#!/bin/sh
cfg=trainer_config.lr.py
#cfg=trainer_config.emb.py
#cfg=trainer_config.cnn.py
#cfg=trainer_config.lstm.py
paddle train \
--config=$cfg \
--save_dir=./output \
--trainer_count=4 \
--log_period=20 \
--num_passes=15 \
--use_gpu=false \
--show_parameter_stats_period=100 \
--test_all_data_in_one_period=1 \
2>&1 | tee 'train.log'
- 关于训练参数的具体含义请参考
- 训练完毕后会在save_dir参数的文件夹下保存训练结果,保存为pass-x形式的文件名,其中x代表遍历全部样本的x次后得到的模型。
预测
预测可以使用有标签的数据对训练好的模型进行评价,也可以直接使用没有label的数据集进行预测。
在测试脚本中将会测试配置文件中test.list指定的数据。
paddle train \
--use_gpu=false \
--job=test \
其中x需要修改为具体训练好的模型。
因为只有时序模型加入了预测的代码,我这里也已时序模型为例说明如何预测没有label的数据。脚本如下:
model="output/pass-x"
paddle train \
--config=trainer_config.lstm.py \
--use_gpu=false \
--job=test \
--init_model_path=$model \
--config_args=is_predict=1 \
--predict_output_dir=. \
其中x需要修改为具体训练好的模型。 得到的标签数据保存在rank-00000中。
- 学习使用paddle之前对神经网络和deep learning基础只是的了解还是很有必要的。
- paddle的源码更新比较快,很有可能出现demo与本文档和官方文档不对应的情况。
- 源码的脚本经常会出现去外网下载数据集的情况,这个可以在本机下载再上传到开发机。
- 非常无奈的是源码还经常会使用pig安装一些Python依赖,这个大家可以首先使用搜索一下是否有响应的安装包,如果没有我通常会在本机安装,然后将site-packages中响应的文件夹拷贝到开发机上。
- 如果使用没有gpu的机器,请将use-gpu设置为0或false。
从2012年开始,深度学习无论是在学术界还是在工业界都引起了极大的关注,深度学习应该说是代表了AI的最高成果。 learning让人一听就是高大上的感觉,但是大部分做的东西其实与数据挖掘无异。机器学习最经典的用法大部分都是从数据中挖掘出一些潜在的规律,这些东西主要包括监督学习(主要包括分类和回归的方法)以及无监督学习(主要包括聚类和降维等方法)。而深度学习只是机器学习的一部分内容。但是深度学习在这些年计算能力的快速增强下的发展壮大,几乎在图像识别,语音识别以及NLP领域已经是深度学习的天下了。 深度学习技术本质上就是具有一定结构的多层神经网络(这里只关心深度学习的模型并没有关注深度学习的优化方法,优化中的trick也是深度学习在实现过程中很重要的一部分)。神经网络的诞生包含着人们对机器智能的渴望,所以在神经网络与传统方法最大的不同就是自己学习特征,利用隐藏层来学习特征,使得在最后的一层的特征变得线性可分。从流形的角度来理解也是很好的角度。请参见。对于一些基本的数据挖掘,只要特征和目标有一定相关性,决策树和支持向量机等方法做的可以和神经网络一样好而且可解释性又强,所以人们往往会冷落神经网络。但是对于图像每个像素作为一个特征,根本无法发现任何的相关性,还有NLP的词向量,这些特征所含有的信息极少,反而是特征之间在空间和时间的邻域内的组合(图像中的图像块和NLP中的句子、段落)对目标的判定具有一定的作用。正因为如此就产生深度学习的经典模型CNN和RNN。这些特殊结构的神经网络一定程度利用特征之间的空域和时域信息取得了很好的效果。他们在构建网络结构时都用了一些局部连接、权重共享、池化和多层网络共享的特点。这篇2015年由,,发表在《nature》上的论文基本介绍了深度学习近几年的发展以及应用,还包含了作者对90年代神经网络被冷落的一些抱怨