-
Notifications
You must be signed in to change notification settings - Fork 0
/
paddle.md
269 lines (207 loc) · 7.55 KB
/
paddle.md
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
# PaddlePaddle
PaddlePaddle 是百度的一款深度学习框架。在开始之前,确保你已经在电脑上装好了
[paddlepaddle](https://www.paddlepaddle.org.cn/)。
````{note}
paddle 是核心代码,paddlex 是更上层的接口。
为了便于理解,可以将 paddle 理解为操作系统,而 paddlex 是运行在操作系统上的应用程序。
除了 paddlex,飞桨 PaddlePaddle 还为我们提供了更多更丰富的上层组件,如下图所示。
```{figure} ../_static/images/paddle-family.png
PaddlePaddle 全家桶
```
使用这些上层组件的前提是,你已经在电脑上装好了 paddlepaddle,因为他们需要使用 paddle 这个底层接口。
````
本文将记录如何使用 paddle,并不对上层工具做具体介绍。
使用 paddle 一般分为三个核心步骤:
1. 定义 transforms 和 datasets;
2. 定义模型(模型组网);
3. 模型训练和预测(模型评估)。
下面以随机生成的数据为样本,测试流程的完整性。
## 定义 transforms 和 datasets
```{code-block} python
import paddle
from paddle.io import Dataset
from paddle.vision.transforms import Compose, Resize
BATCH_SIZE = 64
BATCH_NUM = 20
IMAGE_SIZE = (28, 28)
CLASS_NUM = 10
# 定义自定义数据集
class MyDataset(Dataset):
# 实现构造函数
def __init__(self, num_samples):
super(MyDataset, self).__init__()
# 定义数据集大小
self.num_samples = num_samples
# 定义 transforms 方法,此处为调整图像大小
self.transform = Compose([Resize(size=32)])
# 指定 index 时如何获取数据
def __getitem__(self, index):
# 生成 IMAGE_SIZE 大小的随机数据
data = paddle.uniform(IMAGE_SIZE, dtype='float32')
# 使用 transforms 方法
data = self.transform(data.numpy())
label = paddle.randint(0, CLASS_NUM-1, dtype='int64')
# 返回单条数据(训练数据,对应的标签)
return data, label
# 返回数据集总数目
def __len__(self):
return self.num_samples
```
````{admonition} 内置 datasets 和 transforms
:class: dropdown
视觉相关数据集:
```{code-block} python
['DatasetFolder', 'ImageFolder', 'MNIST', 'FashionMNIST',
'Flowers', 'Cifar10', 'Cifar100', 'VOC2012']
```
自然语言相关数据集:
```{code-block} python
['Conll05st', 'Imdb', 'Imikolov', 'Movielens', 'UCIHousing', 'WMT14', 'WMT16']
```
数据处理方法:
```{code-block} python
['BaseTransform', 'Compose', 'Resize',
'RandomResizedCrop', 'CenterCrop', 'RandomCrop',
'RandomHorizontalFlip', 'RandomVerticalFlip', 'RandomRotation',
'Transpose', 'Normalize',
'BrightnessTransform', 'SaturationTransform', 'ContrastTransform',
'HueTransform', 'ColorJitter', 'Pad', 'Grayscale',
'ToTensor', 'to_tensor', 'hflip', 'vflip', 'resize',
'pad', 'rotate', 'to_grayscale', 'crop', 'center_crop',
'adjust_brightness', 'adjust_contrast', 'adjust_hue', 'normalize']
```
````
## 定义模型(模型组网)
飞桨提供了两种构建模型的方式:
- `Sequential` 组网:针对顺序的线性网络结构;
- `SubClass` 组网:针对一些比较复杂的网络结构。
组网相关的 API 都在 `paddle.nn` 下。
### Sequential 组网
```{code-block} python
myModel = paddle.nn.Sequential(
paddle.nn.Flatten(),
paddle.nn.Linear(784, 512),
paddle.nn.ReLU(),
paddle.nn.Dropout(0.2),
paddle.nn.Linear(512, 10)
)
```
### SubClass 组网
```{code-block} python
class MyModel(paddle.nn.Layer):
def __init__(self):
super(MyModel, self).__init__()
# 对 Layer 进行声明
self.flatten = paddle.nn.Flatten(1, -1)
self.linear_1 = paddle.nn.Linear(1024, 512)
self.linear_2 = paddle.nn.Linear(512, 10)
self.relu = paddle.nn.ReLU()
self.dropout = paddle.nn.Dropout(0.2)
# 定义模型(前向计算)
def forward(self, inputs):
y = self.flatten(inputs)
y = self.linear_1(y)
y = self.relu(y)
y = self.dropout(y)
y = self.linear_2(y)
return y
```
````{admonition} 内置模型
:class: dropdown
飞桨框架内置模型:
```{code-block} python
['ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101', 'resnet152',
'VGG', 'vgg11', 'vgg13', 'vgg16', 'vgg19',
'MobileNetV1', 'mobilenet_v1', 'MobileNetV2', 'mobilenet_v2',
'LeNet']
```
使用方法:
```{code-block} python
lenet = paddle.vision.models.LeNet()
paddle.summary(lenet, (64, 1, 28, 28)) # 查看网络结构
```
````
## 模型训练和预测
飞桨提供了两种方式进行训练和预测:
- 先用 `paddle.Model` 封装模型,再用高层 API:`Model.fit()`,`Model.evaluate()`,`Model.predict()`;
- 直接使用基础 API。
### 使用高层 API
```{code-block} python
# 加载自定义数据集
custom_dataset = MyDataset(BATCH_SIZE * BATCH_NUM)
# 封装模型
myModel = MyModel()
model = paddle.Model(myModel)
# 为模型训练做准备,设置优化器,损失函数和精度计算方式
model.prepare(optimizer=paddle.optimizer.Adam(parameters=model.parameters()),
loss=paddle.nn.CrossEntropyLoss(),
metrics=paddle.metric.Accuracy())
# 启动模型训练,指定训练数据集,设置训练轮次,设置每次数据集计算的批次大小,设置日志格式
model.fit(custom_dataset,
epochs=5,
batch_size=64,
verbose=1)
# 用 evaluate 在测试集上对模型进行验证
eval_result = model.evaluate(custom_dataset, verbose=1)
# 用 predict 在测试集上对模型进行测试
test_result = model.predict(custom_dataset)
```
### 使用基础 API
#### 模型训练
```{code-block} python
# 加载自定义数据集
custom_dataset = MyDataset(BATCH_SIZE * BATCH_NUM)
train_loader = paddle.io.DataLoader(custom_dataset, batch_size=BATCH_SIZE, shuffle=True)
model = MyModel()
model.train()
# 设置优化器,损失函数和精度计算方式
optim = paddle.optimizer.Adam(parameters=model.parameters())
loss_fn = paddle.nn.CrossEntropyLoss()
epochs = 5
for epoch in range(epochs):
for batch_id, data in enumerate(train_loader()):
x_data = data[0] # 训练数据
y_data = data[1] # 标签
# 调用前向计算
predicts = model(x_data)
# 计算损失
loss = loss_fn(predicts, y_data)
# 计算准确率
acc = paddle.metric.accuracy(predicts, y_data)
# 反向传播
loss.backward()
# 输出结果
if (batch_id+1) % 4 == 0:
print("epoch: {}, batch_id: {}, loss is: {}, acc is: {}".format(
epoch+1, batch_id+1, loss.numpy(), acc.numpy()))
# 更新参数
optim.step()
# 参数清零
optim.clear_grad()
```
#### 模型验证
```{code-block} python
test_loader = paddle.io.DataLoader(custom_dataset, batch_size=BATCH_SIZE, shuffle=True)
model.eval()
for batch_id, data in enumerate(test_loader()):
x_data = data[0] # 训练数据
y_data = data[1] # 标签
# 调用前向计算
predicts = model(x_data)
# 计算损失
loss = loss_fn(predicts, y_data)
# 计算准确率
acc = paddle.metric.accuracy(predicts, y_data)
# 模型验证没有反向传播,因此也就不会更新参数
# 输出结果
if (batch_id+1) % 4 == 0:
print("epoch: {}, batch_id: {}, loss is: {}, acc is: {}".format(
epoch+1, batch_id+1, loss.numpy(), acc.numpy()))
```
#### 模型测试
```{code-block} python
for batch_id, data in enumerate(test_loader()):
x_data = data[0] # 训练数据
predicts = model(x_data) # 调用前向计算
print("result: {}".format(predicts.numpy()))
```