-
Notifications
You must be signed in to change notification settings - Fork 2.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add image classification models #52
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
6dd3895
add v2 API for imagenet models
wwhu 8848164
add doc and reorginize net output
wwhu d7d1ae5
minor revision
wwhu 0116bc8
add infer.py and flower dataset
wwhu 208ca38
fix bug for resnet_cifar10 and adjust learning rate
wwhu e9b94ca
fix bug
wwhu bdffa40
add xmap for image list and modify the image reader of infer.py
wwhu cf9cf4c
resolve conflict
wwhu File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,223 @@ | ||
TBD | ||
图像分类 | ||
======================= | ||
|
||
这里将介绍如何在PaddlePaddle下使用AlexNet、VGG、GoogLeNet和ResNet模型进行图像分类。图像分类问题的描述和这四种模型的介绍可以参考[PaddlePaddle book](https://github.com/PaddlePaddle/book/tree/develop/03.image_classification)。 | ||
|
||
## 训练模型 | ||
|
||
### 初始化 | ||
|
||
在初始化阶段需要导入所用的包,并对PaddlePaddle进行初始化。 | ||
|
||
```python | ||
import gzip | ||
import paddle.v2.dataset.flowers as flowers | ||
import paddle.v2 as paddle | ||
import reader | ||
import vgg | ||
import resnet | ||
import alexnet | ||
import googlenet | ||
|
||
|
||
# PaddlePaddle init | ||
paddle.init(use_gpu=False, trainer_count=1) | ||
``` | ||
|
||
### 定义参数和输入 | ||
|
||
设置算法参数(如数据维度、类别数目和batch size等参数),定义数据输入层`image`和类别标签`lbl`。 | ||
|
||
```python | ||
DATA_DIM = 3 * 224 * 224 | ||
CLASS_DIM = 102 | ||
BATCH_SIZE = 128 | ||
|
||
image = paddle.layer.data( | ||
name="image", type=paddle.data_type.dense_vector(DATA_DIM)) | ||
lbl = paddle.layer.data( | ||
name="label", type=paddle.data_type.integer_value(CLASS_DIM)) | ||
``` | ||
|
||
### 获得所用模型 | ||
|
||
这里可以选择使用AlexNet、VGG、GoogLeNet和ResNet模型中的一个模型进行图像分类。通过调用相应的方法可以获得网络最后的Softmax层。 | ||
|
||
1. 使用AlexNet模型 | ||
|
||
指定输入层`image`和类别数目`CLASS_DIM`后,可以通过下面的代码得到AlexNet的Softmax层。 | ||
|
||
```python | ||
out = alexnet.alexnet(image, class_dim=CLASS_DIM) | ||
``` | ||
|
||
2. 使用VGG模型 | ||
|
||
根据层数的不同,VGG分为VGG13、VGG16和VGG19。使用VGG16模型的代码如下: | ||
|
||
```python | ||
out = vgg.vgg16(image, class_dim=CLASS_DIM) | ||
``` | ||
|
||
类似地,VGG13和VGG19可以分别通过`vgg.vgg13`和`vgg.vgg19`方法获得。 | ||
|
||
3. 使用GoogLeNet模型 | ||
|
||
GoogLeNet在训练阶段使用两个辅助的分类器强化梯度信息并进行额外的正则化。因此`googlenet.googlenet`共返回三个Softmax层,如下面的代码所示: | ||
|
||
```python | ||
out, out1, out2 = googlenet.googlenet(image, class_dim=CLASS_DIM) | ||
loss1 = paddle.layer.cross_entropy_cost( | ||
input=out1, label=lbl, coeff=0.3) | ||
paddle.evaluator.classification_error(input=out1, label=lbl) | ||
loss2 = paddle.layer.cross_entropy_cost( | ||
input=out2, label=lbl, coeff=0.3) | ||
paddle.evaluator.classification_error(input=out2, label=lbl) | ||
extra_layers = [loss1, loss2] | ||
``` | ||
|
||
对于两个辅助的输出,这里分别对其计算损失函数并评价错误率,然后将损失作为后文SGD的extra_layers。 | ||
|
||
4. 使用ResNet模型 | ||
|
||
ResNet模型可以通过下面的代码获取: | ||
|
||
```python | ||
out = resnet.resnet_imagenet(image, class_dim=CLASS_DIM) | ||
``` | ||
|
||
### 定义损失函数 | ||
|
||
```python | ||
cost = paddle.layer.classification_cost(input=out, label=lbl) | ||
``` | ||
|
||
### 创建参数和优化方法 | ||
|
||
```python | ||
# Create parameters | ||
parameters = paddle.parameters.create(cost) | ||
|
||
# Create optimizer | ||
optimizer = paddle.optimizer.Momentum( | ||
momentum=0.9, | ||
regularization=paddle.optimizer.L2Regularization(rate=0.0005 * | ||
BATCH_SIZE), | ||
learning_rate=0.001 / BATCH_SIZE, | ||
learning_rate_decay_a=0.1, | ||
learning_rate_decay_b=128000 * 35, | ||
learning_rate_schedule="discexp", ) | ||
``` | ||
|
||
通过 `learning_rate_decay_a` (简写$a$) 、`learning_rate_decay_b` (简写$b$) 和 `learning_rate_schedule` 指定学习率调整策略,这里采用离散指数的方式调节学习率,计算公式如下, $n$ 代表已经处理过的累计总样本数,$lr_{0}$ 即为参数里设置的 `learning_rate`。 | ||
|
||
$$ lr = lr_{0} * a^ {\lfloor \frac{n}{ b}\rfloor} $$ | ||
|
||
|
||
### 定义数据读取 | ||
|
||
首先以[花卉数据](http://www.robots.ox.ac.uk/~vgg/data/flowers/102/index.html)为例说明如何定义输入。下面的代码定义了花卉数据训练集和验证集的输入: | ||
|
||
```python | ||
train_reader = paddle.batch( | ||
paddle.reader.shuffle( | ||
flowers.train(), | ||
buf_size=1000), | ||
batch_size=BATCH_SIZE) | ||
test_reader = paddle.batch( | ||
flowers.valid(), | ||
batch_size=BATCH_SIZE) | ||
``` | ||
|
||
若需要使用其他数据,则需要先建立图像列表文件。`reader.py`定义了这种文件的读取方式,它从图像列表文件中解析出图像路径和类别标签。 | ||
|
||
图像列表文件是一个文本文件,其中每一行由一个图像路径和类别标签构成,二者以跳格符(Tab)隔开。类别标签用整数表示,其最小值为0。下面给出一个图像列表文件的片段示例: | ||
|
||
``` | ||
dataset_100/train_images/n03982430_23191.jpeg 1 | ||
dataset_100/train_images/n04461696_23653.jpeg 7 | ||
dataset_100/train_images/n02441942_3170.jpeg 8 | ||
dataset_100/train_images/n03733281_31716.jpeg 2 | ||
dataset_100/train_images/n03424325_240.jpeg 0 | ||
dataset_100/train_images/n02643566_75.jpeg 8 | ||
``` | ||
|
||
训练时需要分别指定训练集和验证集的图像列表文件。这里假设这两个文件分别为`train.list`和`val.list`,数据读取方式如下: | ||
|
||
```python | ||
train_reader = paddle.batch( | ||
paddle.reader.shuffle( | ||
reader.train_reader('train.list'), | ||
buf_size=1000), | ||
batch_size=BATCH_SIZE) | ||
test_reader = paddle.batch( | ||
reader.test_reader('val.list'), | ||
batch_size=BATCH_SIZE) | ||
``` | ||
|
||
### 定义事件处理程序 | ||
```python | ||
# End batch and end pass event handler | ||
def event_handler(event): | ||
if isinstance(event, paddle.event.EndIteration): | ||
if event.batch_id % 1 == 0: | ||
print "\nPass %d, Batch %d, Cost %f, %s" % ( | ||
event.pass_id, event.batch_id, event.cost, event.metrics) | ||
if isinstance(event, paddle.event.EndPass): | ||
with gzip.open('params_pass_%d.tar.gz' % event.pass_id, 'w') as f: | ||
parameters.to_tar(f) | ||
|
||
result = trainer.test(reader=test_reader) | ||
print "\nTest with Pass %d, %s" % (event.pass_id, result.metrics) | ||
``` | ||
|
||
### 定义训练方法 | ||
|
||
对于AlexNet、VGG和ResNet,可以按下面的代码定义训练方法: | ||
|
||
```python | ||
# Create trainer | ||
trainer = paddle.trainer.SGD( | ||
cost=cost, | ||
parameters=parameters, | ||
update_equation=optimizer) | ||
``` | ||
|
||
GoogLeNet有两个额外的输出层,因此需要指定`extra_layers`,如下所示: | ||
|
||
```python | ||
# Create trainer | ||
trainer = paddle.trainer.SGD( | ||
cost=cost, | ||
parameters=parameters, | ||
update_equation=optimizer, | ||
extra_layers=extra_layers) | ||
``` | ||
|
||
### 开始训练 | ||
|
||
```python | ||
trainer.train( | ||
reader=train_reader, num_passes=200, event_handler=event_handler) | ||
``` | ||
|
||
## 应用模型 | ||
模型训练好后,可以使用下面的代码预测给定图片的类别。 | ||
|
||
```python | ||
# load parameters | ||
with gzip.open('params_pass_10.tar.gz', 'r') as f: | ||
parameters = paddle.parameters.Parameters.from_tar(f) | ||
|
||
file_list = [line.strip() for line in open(image_list_file)] | ||
test_data = [(paddle.image.load_and_transform(image_file, 256, 224, False) | ||
.flatten().astype('float32'), ) | ||
for image_file in file_list] | ||
probs = paddle.infer( | ||
output_layer=out, parameters=parameters, input=test_data) | ||
lab = np.argsort(-probs) | ||
for file_name, result in zip(file_list, lab): | ||
print "Label of %s is: %d" % (file_name, result[0]) | ||
``` | ||
|
||
首先从文件中加载训练好的模型(代码里以第10轮迭代的结果为例),然后读取`image_list_file`中的图像。`image_list_file`是一个文本文件,每一行为一个图像路径。代码使用`paddle.infer`判断`image_list_file`中每个图像的类别,并进行输出。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import paddle.v2 as paddle | ||
|
||
__all__ = ['alexnet'] | ||
|
||
|
||
def alexnet(input, class_dim): | ||
conv1 = paddle.layer.img_conv( | ||
input=input, | ||
filter_size=11, | ||
num_channels=3, | ||
num_filters=96, | ||
stride=4, | ||
padding=1) | ||
cmrnorm1 = paddle.layer.img_cmrnorm( | ||
input=conv1, size=5, scale=0.0001, power=0.75) | ||
pool1 = paddle.layer.img_pool(input=cmrnorm1, pool_size=3, stride=2) | ||
|
||
conv2 = paddle.layer.img_conv( | ||
input=pool1, | ||
filter_size=5, | ||
num_filters=256, | ||
stride=1, | ||
padding=2, | ||
groups=1) | ||
cmrnorm2 = paddle.layer.img_cmrnorm( | ||
input=conv2, size=5, scale=0.0001, power=0.75) | ||
pool2 = paddle.layer.img_pool(input=cmrnorm2, pool_size=3, stride=2) | ||
|
||
pool3 = paddle.networks.img_conv_group( | ||
input=pool2, | ||
pool_size=3, | ||
pool_stride=2, | ||
conv_num_filter=[384, 384, 256], | ||
conv_filter_size=3, | ||
pool_type=paddle.pooling.Max()) | ||
|
||
fc1 = paddle.layer.fc( | ||
input=pool3, | ||
size=4096, | ||
act=paddle.activation.Relu(), | ||
layer_attr=paddle.attr.Extra(drop_rate=0.5)) | ||
fc2 = paddle.layer.fc( | ||
input=fc1, | ||
size=4096, | ||
act=paddle.activation.Relu(), | ||
layer_attr=paddle.attr.Extra(drop_rate=0.5)) | ||
|
||
out = paddle.layer.fc( | ||
input=fc2, size=class_dim, act=paddle.activation.Softmax()) | ||
return out |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
learning_rate_decay_a, learning_rate_decay_b解释下吧,参见book里的解释~