作为一名初步进入深度学习领域的小白来说,复杂的命令行操作,一些看不懂的专业英语术语,满篇的英文接口与方法,经常让人感到烦恼甚至劝退。然而,作为国产的深度学习框架工具,飞桨提供了一个完全国产化的平台,功能强大而且丰富。本文为刚刚接触paddle框架的小白排雷,顺便阐述飞桨框架的一些使用技巧,防止新手因为信息量过于庞大或者不善于查找资料而烦恼
在ai studio中,paddle框架的学习是结合jupyter notebook一起使用的,因而为了使用简便,建议预先安装jupyter notebook(有pytorch和anaconda使用经历的大佬们电脑中一般已经有了,可以先查看一下)
对于安装有GPU或者使用的笔记本电脑显卡为NVIDIA的用户,推荐安装pycharm以便获取更快速的代码运行速度(虽然飞桨官方有算力卡,提供CPU和GPU服务,但是以后总会在自己电脑上跑的呀)。GPU的环境下运行速度显著快于CPU,更改使用环境参考代码:with fluid.dygraph.guard(place),在place赋值时可供选择
use_gpu = True
place = fluid.CUDAPlace(0) if use_gpu else fluid.CPUPlace()
其中0代表0号GPU卡,一般配置有GPU的电脑都是4卡,查找卡的名称及使用情况,请使用命令行输入:
启动多GPU的训练,还需要在命令行中设置一些参数变量。打开终端,运行如下命令:
$ python -m paddle.distributed.launch --selected_gpus=0,1,2,3 --log_dir ./mylog train_multi_gpu.py
paddle.distributed.launch:启动分布式运行。
selected_gpus:设置使用的GPU的序号(需要是多GPU卡的机器,通过命令watch nvidia-smi查看GPU的序号)。
log_dir:存放训练的log,若不设置,每个GPU上的训练信息都会打印到屏幕。
train_multi_gpu.py:多GPU训练的程序,包含修改过的train_multi_gpu()函数。
注意,使用GPU训练时代码和CPU有三处差异:以mnist数据集的训练过程为例,在修改过的train_multi_gpu()函数中:
#GPU训练过程:
def train_multi_gpu():
##修改1-从环境变量获取使用GPU的序号
place = fluid.CUDAPlace(fluid.dygraph.parallel.Env().dev_id)
with fluid.dygraph.guard(place):
##修改2-对原模型做并行化预处理
strategy = fluid.dygraph.parallel.prepare_context()
model = MNIST()
model = fluid.dygraph.parallel.DataParallel(model, strategy)
model.train()
# 调用加载数据的函数
train_loader = load_data('train')
##修改3-多GPU数据读取,必须确保每个进程读取的数据是不同的
train_loader = fluid.contrib.reader.distributed_batch_reader(train_loader)
optimizer = fluid.optimizer.SGDOptimizer(learning_rate=0.01, parameter_list=model.parameters())
EPOCH_NUM = 5
for epoch_id in range(EPOCH_NUM):
for batch_id, data in enumerate(train_loader()):
# 准备数据
image_data, label_data = data
image = fluid.dygraph.to_variable(image_data)
label = fluid.dygraph.to_variable(label_data)
predict = model(image)
loss = fluid.layers.cross_entropy(predict, label)
avg_loss = fluid.layers.mean(loss)
# 修改4-多GPU训练需要对Loss做出调整,并聚合不同设备上的参数梯度
avg_loss = model.scale_loss(avg_loss)
avg_loss.backward()
model.apply_collective_grads()
# 最小化损失函数,清除本次训练的梯度
optimizer.minimize(avg_loss)
model.clear_gradients()
if batch_id % 200 == 0:
print("epoch: {}, batch: {}, loss is: {}".format(epoch_id, batch_id, avg_loss.numpy()))
# 保存模型参数
fluid.save_dygraph(model.state_dict(), 'mnist')
这三个是安装,运行paddle所需要的库,需要提前安装。安装时推荐使用清华源安装,换源的具体代码同下面paddle安装。注意,python3及的用户安装python时默认同时安装了pip,可以通过使用命令
pip -V
查看现有pip版本,未安装则会报错。已经有pip的用户可以使用命令
pip list
查看现有的通过pip安装的包,如numpy,matplotlib。有过机器学习编程基础或者接触矩阵等数学运算在计算机上的操作的同学,一般都已经安装过了。
我当时自己安装paddle,也算是有点基础,之前因为接触过自动机器学习项目(nni),安装过tensorflow和nni,其实和paddle安装经历差不多,主要就是命令行操作加python代码验证。
注意,python3.8不能使用paddle,推荐使用3.5(更稳定)或者3.7安装,具体情况看你现有的python版本。而且,安装时强烈建议关闭其他所有联网软件!!!网速会有显著提高的
acanonda安装方法:(推荐,好管理)
#在命令行窗口CMD中:
#创建虚拟环境
F:\>conda create --name paddle python=3.5
F:\>activate paddle
#添加清华源,如果卡顿,可以自己换成百度源
F:\>conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
F:\>conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
F:\>conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/Paddle/
#如果安装终断,从这行开始重复执行,直到成功
F:\>conda config --set show_channel_urls yes
F:\>conda install paddlepaddle #CPU 不是NIVDIA显卡用这个
F:\>conda install paddlepaddle-gpu cudatoolkit=10.0 #GPU NIVDIA显卡用这个,自带CUDA和CUDNN
#检验:
F:\>python
F:\>import paddle.fluid
F:\>paddle.fluid.install_check.run_check()
#如果出现 Your Paddle Fluid is installed successfully!,说明您已成功安装。
#每次重新进入环境(在CMD下):
F:\>activate paddle
如果程序进度条卡死不懂超过两分钟,建议直接关闭窗口再次安装,很可能是因为你之前没有关闭所有联网软件,安装时这些软件占用网络。我当初重复了4次,成功了(家里的网太慢了,总是卡)
解释器设置为\Anaconda\envs\paddle的python.exe 重要!!!(包括每个项目的解释器)
如:pycharm设置:Configure->Settings->Project Interpreter->齿轮->add->System Interpreter->文件夹\Anaconda\envs\paddle下的python.exe->OK,OK
每个项目的设置也是:File->Settings->Project:->Project Interpreter->下拉菜单->Anaconda\envs\paddle下的python.exe
另:
anaconda中查看Python版本号: F:>python -V #注意V是大写
确认 Python 和 pip 是 64 位:
python3 -c “import platform;print(platform.architecture()[0]);print(platform.machine())”
想要利用好paddle框架,其实也是需要深厚的python基础的,因为一些对于列表中元素的操作,库中的方法的灵活调用(数据处理模块为例),很可能会导致新人感觉代码晦涩难懂,需要自己一个个的baidu接口。
python代码中,数据处理,读入数据,处理器,网络建模编写,训练,检验等,都需要用户自己编写,工作量动辄500行左右,而且还不算网络部分的优化算法编写,损失函数的寻找,激活函数的选择与定义。如果这些工作都让用户去做,工作量太大。
以最简单的Network为例,连loss函数这样简单做差的函数都要自己定义,那么如果采用复杂的形式,比如方差等,python直接编写神经网络的缺点就凸显出来了,不够方便。
class Network(object):
def __init__(self, num_of_weights):
# 随机产生w的初始值
# 为了保持程序每次运行结果的一致性,此处设置固定的随机数种子
# np.random.seed(0)
self.w = np.random.randn(num_of_weights, 1)
self.b = 0.
def forward(self, x):
z = np.dot(x, self.w) + self.b
return z
def loss(self, z, y):
error = z - y
num_samples = error.shape[0]
cost = error * error
cost = np.sum(cost) / num_samples
return cost
def gradient(self, x, y):
z = self.forward(x)
N = x.shape[0]
gradient_w = 1. / N * np.sum((z - y) * x, axis=0)
gradient_w = gradient_w[:, np.newaxis]
gradient_b = 1. / N * np.sum(z - y)
return gradient_w, gradient_b
def update(self, gradient_w, gradient_b, eta=0.01):
self.w = self.w - eta * gradient_w
self.b = self.b - eta * gradient_b
def train(self, training_data, num_epoches, batch_size=10, eta=0.01):
n = len(training_data)
losses = []
for epoch_id in range(num_epoches):
# 在每轮迭代开始之前,将训练数据的顺序随机打乱
# 然后再按每次取batch_size条数据的方式取出
np.random.shuffle(training_data)
# 将训练数据进行拆分,每个mini_batch包含batch_size条的数据
mini_batches = [training_data[k:k + batch_size] for k in range(0, n, batch_size)]
for iter_id, mini_batch in enumerate(mini_batches):
# print(self.w.shape)
# print(self.b)
x = mini_batch[:, :-1]
y = mini_batch[:, -1:]
a = self.forward(x)
loss = self.loss(a, y)
gradient_w, gradient_b = self.gradient(x, y)
self.update(gradient_w, gradient_b, eta)
losses.append(loss)
print('Epoch {:3d} / iter {:3d}, loss = {:.4f}'.
format(epoch_id, iter_id, loss))
return losses
但是paddle中有现成的接口,上述的各项操作,比如损失函数,激活函数,优化算法,设计器,在paddle中基本都是一两行代码,直接导入结束,十分简单。不仅如此,飞桨还提供了大量不同的优化策略等,供同学们探索。同学们可以在自己模型中摸索尝试,体会不同策略对于模型梯度,loss变化的影响。
代码详情查看飞桨官方api文档:https://www.paddlepaddle.org.cn/documentation/docs/zh/api_cn/index_cn.html
paddle中尤其要求灵活使用numpy中的各种操作,比如元素变换,矩阵转置,shape,reshape,mean方法,std方法等。建议查看代码之前优先看一下numpy的帮助文档。
欢迎有问题的小伙伴在下方留言,共同进步!