test_recognize_digits.py 8.9 KB
Newer Older
1
#   Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
Y
Yang Yu 已提交
2 3 4 5 6 7 8 9 10 11 12 13 14 15
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import print_function
import argparse
16
import paddle.fluid as fluid
Y
Yang Yu 已提交
17 18
import paddle.v2 as paddle
import sys
Y
Yang Yu 已提交
19
import numpy
20
import unittest
21 22
import math
import sys
Y
Yang Yu 已提交
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


def parse_arg():
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "nn_type",
        help="The neural network type, in ['mlp', 'conv']",
        type=str,
        choices=['mlp', 'conv'])
    parser.add_argument(
        "--parallel",
        help='Run in parallel or not',
        default=False,
        action="store_true")
    parser.add_argument(
        "--use_cuda",
        help="Run the program by using CUDA",
        default=False,
        action="store_true")
    return parser.parse_args()


BATCH_SIZE = 64


def loss_net(hidden, label):
    prediction = fluid.layers.fc(input=hidden, size=10, act='softmax')
    loss = fluid.layers.cross_entropy(input=prediction, label=label)
Y
Yu Yang 已提交
51
    avg_loss = fluid.layers.mean(loss)
L
Liu Yiqun 已提交
52 53
    acc = fluid.layers.accuracy(input=prediction, label=label)
    return prediction, avg_loss, acc
Y
Yang Yu 已提交
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69


def mlp(img, label):
    hidden = fluid.layers.fc(input=img, size=200, act='tanh')
    hidden = fluid.layers.fc(input=hidden, size=200, act='tanh')
    return loss_net(hidden, label)


def conv_net(img, label):
    conv_pool_1 = fluid.nets.simple_img_conv_pool(
        input=img,
        filter_size=5,
        num_filters=20,
        pool_size=2,
        pool_stride=2,
        act="relu")
Y
Yang Yang(Tony) 已提交
70
    conv_pool_1 = fluid.layers.batch_norm(conv_pool_1)
Y
Yang Yu 已提交
71 72 73 74 75 76 77 78 79 80
    conv_pool_2 = fluid.nets.simple_img_conv_pool(
        input=conv_pool_1,
        filter_size=5,
        num_filters=50,
        pool_size=2,
        pool_stride=2,
        act="relu")
    return loss_net(conv_pool_2, label)


81 82 83 84 85 86
def train(nn_type,
          use_cuda,
          parallel,
          save_dirname=None,
          model_filename=None,
          params_filename=None):
87 88
    if use_cuda and not fluid.core.is_compiled_with_cuda():
        return
Y
Yang Yu 已提交
89 90 91
    img = fluid.layers.data(name='img', shape=[1, 28, 28], dtype='float32')
    label = fluid.layers.data(name='label', shape=[1], dtype='int64')

92
    if nn_type == 'mlp':
Y
Yang Yu 已提交
93 94 95 96
        net_conf = mlp
    else:
        net_conf = conv_net

97
    if parallel:
Y
Yang Yu 已提交
98 99 100 101 102
        places = fluid.layers.get_places()
        pd = fluid.layers.ParallelDo(places)
        with pd.do():
            img_ = pd.read_input(img)
            label_ = pd.read_input(label)
L
Liu Yiqun 已提交
103 104
            prediction, avg_loss, acc = net_conf(img_, label_)
            for o in [avg_loss, acc]:
Y
Yang Yu 已提交
105 106 107 108
                pd.write_output(o)

        avg_loss, acc = pd()
        # get mean loss and acc through every devices.
Y
Yu Yang 已提交
109 110
        avg_loss = fluid.layers.mean(avg_loss)
        acc = fluid.layers.mean(acc)
Y
Yang Yu 已提交
111
    else:
L
Liu Yiqun 已提交
112
        prediction, avg_loss, acc = net_conf(img, label)
Y
Yang Yu 已提交
113

Y
Yang Yu 已提交
114 115
    test_program = fluid.default_main_program().clone()

Y
Yang Yu 已提交
116 117 118
    optimizer = fluid.optimizer.Adam(learning_rate=0.001)
    optimizer.minimize(avg_loss)

119
    place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace()
Y
Yang Yu 已提交
120 121 122 123 124 125 126 127

    exe = fluid.Executor(place)
    exe.run(fluid.default_startup_program())

    train_reader = paddle.batch(
        paddle.reader.shuffle(
            paddle.dataset.mnist.train(), buf_size=500),
        batch_size=BATCH_SIZE)
Y
Yang Yu 已提交
128 129
    test_reader = paddle.batch(
        paddle.dataset.mnist.test(), batch_size=BATCH_SIZE)
Y
Yang Yu 已提交
130 131 132 133 134
    feeder = fluid.DataFeeder(feed_list=[img, label], place=place)

    PASS_NUM = 100
    for pass_id in range(PASS_NUM):
        for batch_id, data in enumerate(train_reader()):
Y
Yang Yu 已提交
135 136
            # train a mini-batch, fetch nothing
            exe.run(feed=feeder.feed(data))
Y
Yang Yu 已提交
137
            if (batch_id + 1) % 10 == 0:
Y
Yang Yu 已提交
138 139 140 141 142 143 144 145 146 147 148
                acc_set = []
                avg_loss_set = []
                for test_data in test_reader():
                    acc_np, avg_loss_np = exe.run(program=test_program,
                                                  feed=feeder.feed(test_data),
                                                  fetch_list=[acc, avg_loss])
                    acc_set.append(float(acc_np))
                    avg_loss_set.append(float(avg_loss_np))
                # get test acc and loss
                acc_val = numpy.array(acc_set).mean()
                avg_loss_val = numpy.array(avg_loss_set).mean()
149
                if float(acc_val) > 0.2:  # Smaller value to increase CI speed
L
Liu Yiqun 已提交
150
                    if save_dirname is not None:
151 152 153
                        fluid.io.save_inference_model(
                            save_dirname, ["img"], [prediction],
                            exe,
154 155
                            model_filename=model_filename,
                            params_filename=params_filename)
L
Liu Yiqun 已提交
156
                    return
Y
Yang Yu 已提交
157 158
                else:
                    print(
Y
Yang Yu 已提交
159
                        'PassID {0:1}, BatchID {1:04}, Test Loss {2:2.2}, Acc {3:2.2}'.
Y
Yang Yu 已提交
160
                        format(pass_id, batch_id + 1,
Y
Yang Yu 已提交
161
                               float(avg_loss_val), float(acc_val)))
162 163
                    if math.isnan(float(avg_loss_val)):
                        sys.exit("got NaN loss, training failed.")
164
    raise AssertionError("Loss of recognize digits is too large")
Y
Yang Yu 已提交
165 166


167 168 169 170
def infer(use_cuda,
          save_dirname=None,
          model_filename=None,
          params_filename=None):
L
Liu Yiqun 已提交
171 172 173
    if save_dirname is None:
        return

174
    place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace()
L
Liu Yiqun 已提交
175 176
    exe = fluid.Executor(place)

177 178 179 180 181 182
    inference_scope = fluid.core.Scope()
    with fluid.scope_guard(inference_scope):
        # Use fluid.io.load_inference_model to obtain the inference program desc,
        # the feed_target_names (the names of variables that will be feeded
        # data using feed operators), and the fetch_targets (variables that
        # we want to obtain data from using fetch operators).
183 184 185
        [inference_program, feed_target_names,
         fetch_targets] = fluid.io.load_inference_model(
             save_dirname, exe, model_filename, params_filename)
186 187 188 189 190 191 192 193 194 195 196 197 198

        # The input's dimension of conv should be 4-D or 5-D.
        # Use normilized image pixels as input data, which should be in the range [-1.0, 1.0].
        batch_size = 1
        tensor_img = numpy.random.uniform(
            -1.0, 1.0, [batch_size, 1, 28, 28]).astype("float32")

        # Construct feed as a dictionary of {feed_target_name: feed_target_data}
        # and results will contain a list of data corresponding to fetch_targets.
        results = exe.run(inference_program,
                          feed={feed_target_names[0]: tensor_img},
                          fetch_list=fetch_targets)
        print("infer results: ", results[0])
L
Liu Yiqun 已提交
199 200


201
def main(use_cuda, parallel, nn_type, combine):
202 203 204
    save_dirname = None
    model_filename = None
    params_filename = None
205 206
    if not use_cuda and not parallel:
        save_dirname = "recognize_digits_" + nn_type + ".inference.model"
207
        if combine == True:
208 209
            model_filename = "__model_combined__"
            params_filename = "__params_combined__"
210 211 212 213 214

    train(
        nn_type=nn_type,
        use_cuda=use_cuda,
        parallel=parallel,
215
        save_dirname=save_dirname,
216 217
        model_filename=model_filename,
        params_filename=params_filename)
218 219 220
    infer(
        use_cuda=use_cuda,
        save_dirname=save_dirname,
221 222
        model_filename=model_filename,
        params_filename=params_filename)
223 224 225 226 227 228


class TestRecognizeDigits(unittest.TestCase):
    pass


229
def inject_test_method(use_cuda, parallel, nn_type, combine):
230 231 232 233 234 235
    def __impl__(self):
        prog = fluid.Program()
        startup_prog = fluid.Program()
        scope = fluid.core.Scope()
        with fluid.scope_guard(scope):
            with fluid.program_guard(prog, startup_prog):
236
                main(use_cuda, parallel, nn_type, combine)
237

238 239 240 241
    fn = 'test_{0}_{1}_{2}_{3}'.format(nn_type, 'cuda'
                                       if use_cuda else 'cpu', 'parallel'
                                       if parallel else 'normal', 'combine'
                                       if combine else 'separate')
242 243 244 245 246 247 248 249

    setattr(TestRecognizeDigits, fn, __impl__)


def inject_all_tests():
    for use_cuda in (False, True):
        for parallel in (False, True):
            for nn_type in ('mlp', 'conv'):
250 251
                inject_test_method(use_cuda, parallel, nn_type, True)

252
    # Two unit-test for saving parameters as separate files
253
    inject_test_method(False, False, 'mlp', False)
254
    inject_test_method(False, False, 'conv', False)
255 256 257 258 259 260


inject_all_tests()

if __name__ == '__main__':
    unittest.main()