這是一個demo 項目,用於演示如何在 AI Studio 上訓練一個「小」模型,而後把它轉化成一個能夠部署到Paddle派硬件上的模型。html
爲了簡單起見,在此只訓練一個貓貓和狗狗的二分類模型。linux
進入項目時,已經引用了 AI Studio 的公開數據集"貓狗大戰數據集"做爲訓練數據。數據存儲在 data/data62/ 目錄下,以壓縮包的形式存在。執行下面的代碼,進入目錄,將訓練數據解壓網絡
In[1]dom
!cd /home/aistudio/data/data62 && unzip -q train.zip !cd /home/aistudio/data/data62 && unzip -q test.zip
訓練集中的數據按照ide
cat.123.jpg函數
dog.456.jpg工具
的命名方式。因爲數據中存在一些破損的圖片,因此須要先清洗一下數據。同時,爲了方便訓練,將數據的一行準備成學習
文件名\t類別fetch
的格式,並輸出到和圖片同級目錄下的label.txt文件中。貓貓的類別是1,狗狗的類別是0。執行如下代碼,進行數據的簡單清洗優化
In[2]
#數據清洗 import codecs import os from PIL import Image train_file_list = os.listdir('data/data62/train') with codecs.open("data/data62/train/label.txt", 'w') as out_file: for file in train_file_list: try: img = Image.open(os.path.join('data/data62/train', file)) if file.find('cat') != -1: out_file.write("{0}\t{1}\n".format(file, 1)) else: out_file.write("{0}\t{1}\n".format(file, 0)) except Exception as e: pass # 存在一些文件打不開,此處須要稍做清洗
設置基礎訓練參數,例如
其中類別數量會在讀取數據時提早計算,初始爲-1,僅用做佔位
In[3]
from __future__ import absolute_import from __future__ import division from __future__ import print_function import os import numpy as np import uuid import random import time import six import sys import functools import math import paddle import paddle.fluid as fluid import paddle.dataset.flowers as flowers import argparse import functools import subprocess import codecs import distutils.util from paddle.fluid import core from paddle.fluid.initializer import MSRA from paddle.fluid.param_attr import ParamAttr from PIL import Image, ImageEnhance import logging train_parameters = { "input_size": [3, 224, 224], "class_dim": -1, "data_dir": "data/data62/train", "save_model_dir": "./classify-model", "mode": "train", "num_epochs": 120, "image_count": -1, "train_batch_size": 50, "mean_rgb": [127.5, 127.5, 127.5], "use_gpu": True, # 根據本身的環境,選擇適當的設備進行訓練 "image_distort_strategy": { "need_distort": True, "expand_prob": 0.5, "expand_max_ratio": 4, "hue_prob": 0.5, "hue_delta": 18, "contrast_prob": 0.5, "contrast_delta": 0.5, "saturation_prob": 0.5, "saturation_delta": 0.5, "brightness_prob": 0.5, "brightness_delta": 0.125 }, "rsm_strategy": { "learning_rate": 0.02, "lr_epochs": [20, 40, 60, 80, 100], "lr_decay": [1, 0.5, 0.25, 0.1, 0.01, 0.002] }, "momentum_strategy": { "learning_rate": 0.005, "lr_epochs": [20, 40, 60, 80, 100], "lr_decay": [1, 0.5, 0.25, 0.1, 0.01, 0.002] } }
設定網絡結構,此處定義了三個經常使用的網絡結構
爲了訓練一個小模型,此處使用mobile-net。若是是其餘項目或者其餘用途,使用其餘網絡結構亦可
In[4]
class ResNet(): def __init__(self, layers=50): self.layers = layers def name(self): return 'resnet' def net(self, input, class_dim=1000): layers = self.layers supported_layers = [50, 101, 152] assert layers in supported_layers, \ "supported layers are {} but input layer is {}".format(supported_layers, layers) if layers == 50: depth = [3, 4, 6, 3] elif layers == 101: depth = [3, 4, 23, 3] elif layers == 152: depth = [3, 8, 36, 3] num_filters = [64, 128, 256, 512] conv = self.conv_bn_layer( input=input, num_filters=64, filter_size=7, stride=2, act='relu', name="conv1") conv = fluid.layers.pool2d( input=conv, pool_size=3, pool_stride=2, pool_padding=1, pool_type='max') for block in range(len(depth)): for i in range(depth[block]): if layers in [101, 152] and block == 2: if i == 0: conv_name = "res" + str(block + 2) + "a" else: conv_name = "res" + str(block + 2) + "b" + str(i) else: conv_name = "res" + str(block + 2) + chr(97 + i) conv = self.bottleneck_block( input=conv, num_filters=num_filters[block], stride=2 if i == 0 and block != 0 else 1, name=conv_name) pool = fluid.layers.pool2d( input=conv, pool_size=7, pool_type='avg', global_pooling=True) stdv = 1.0 / math.sqrt(pool.shape[1] * 1.0) out = fluid.layers.fc(input=pool, size=class_dim, act='softmax', param_attr=fluid.param_attr.ParamAttr( initializer=fluid.initializer.Uniform(-stdv, stdv))) return out def conv_bn_layer(self, input, num_filters, filter_size, stride=1, groups=1, act=None, name=None): conv = fluid.layers.conv2d( input=input, num_filters=num_filters, filter_size=filter_size, stride=stride, padding=(filter_size - 1) // 2, groups=groups, act=None, param_attr=ParamAttr(name=name + "_weights"), bias_attr=False, name=name + '.conv2d.output.1') if name == "conv1": bn_name = "bn_" + name else: bn_name = "bn" + name[3:] return fluid.layers.batch_norm( input=conv, act=act, name=bn_name + '.output.1', param_attr=ParamAttr(name=bn_name + '_scale'), bias_attr=ParamAttr(bn_name + '_offset'), moving_mean_name=bn_name + '_mean', moving_variance_name=bn_name + '_variance', ) def shortcut(self, input, ch_out, stride, name): ch_in = input.shape[1] if ch_in != ch_out or stride != 1: return self.conv_bn_layer(input, ch_out, 1, stride, name=name) else: return input def bottleneck_block(self, input, num_filters, stride, name): conv0 = self.conv_bn_layer( input=input, num_filters=num_filters, filter_size=1, act='relu', name=name + "_branch2a") conv1 = self.conv_bn_layer( input=conv0, num_filters=num_filters, filter_size=3, stride=stride, act='relu', name=name + "_branch2b") conv2 = self.conv_bn_layer( input=conv1, num_filters=num_filters * 4, filter_size=1, act=None, name=name + "_branch2c") short = self.shortcut( input, num_filters * 4, stride, name=name + "_branch1") return fluid.layers.elementwise_add( x=short, y=conv2, act='relu', name=name + ".add.output.5") class MobileNet(): def __init__(self): pass def name(self): return 'mobile-net' def net(self, input, class_dim=1000, scale=1.0): # conv1: 112x112 input = self.conv_bn_layer( input, filter_size=3, num_filters=int(32 * scale), stride=2, padding=1) # 56x56 input = self.depthwise_separable( input, num_filters1=32, num_filters2=64, num_groups=32, stride=1, scale=scale) input = self.depthwise_separable( input, num_filters1=64, num_filters2=128, num_groups=64, stride=2, scale=scale) # 28x28 input = self.depthwise_separable( input, num_filters1=128, num_filters2=128, num_groups=128, stride=1, scale=scale) input = self.depthwise_separable( input, num_filters1=128, num_filters2=256, num_groups=128, stride=2, scale=scale) # 14x14 input = self.depthwise_separable( input, num_filters1=256, num_filters2=256, num_groups=256, stride=1, scale=scale) input = self.depthwise_separable( input, num_filters1=256, num_filters2=512, num_groups=256, stride=2, scale=scale) # 14x14 for i in range(5): input = self.depthwise_separable( input, num_filters1=512, num_filters2=512, num_groups=512, stride=1, scale=scale) module1 = input # 7x7 input = self.depthwise_separable( input, num_filters1=512, num_filters2=1024, num_groups=512, stride=2, scale=scale) input = self.depthwise_separable( input, num_filters1=1024, num_filters2=1024, num_groups=1024, stride=1, scale=scale) # class_dim x 1 input = paddle.fluid.layers.conv2d( input, num_filters=class_dim, filter_size=1, stride=1) pool = fluid.layers.pool2d( input=input, pool_size=0, pool_stride=1, pool_type='avg', global_pooling=True) output = fluid.layers.fc(input=pool, size=class_dim, act='softmax', param_attr=ParamAttr(initializer=MSRA())) return output def conv_bn_layer(self, input, filter_size, num_filters, stride, padding, num_groups=1, act='relu', use_cudnn=True): conv = fluid.layers.conv2d( input=input, num_filters=num_filters, filter_size=filter_size, stride=stride, padding=padding, groups=num_groups, act=None, use_cudnn=use_cudnn, param_attr=ParamAttr(initializer=MSRA()), bias_attr=False) return fluid.layers.batch_norm(input=conv, act=act) def depthwise_separable(self, input, num_filters1, num_filters2, num_groups, stride, scale): depthwise_conv = self.conv_bn_layer( input=input, filter_size=3, num_filters=int(num_filters1 * scale), stride=stride, padding=1, num_groups=int(num_groups * scale), use_cudnn=True) pointwise_conv = self.conv_bn_layer( input=depthwise_conv, filter_size=1, num_filters=int(num_filters2 * scale), stride=1, padding=0) return pointwise_conv class VGGNet(): def __init__(self, layers=16): self.layers = layers def name(self): return 'vgg-net' def net(self, input, class_dim=1000): layers = self.layers vgg_spec = { 11: ([1, 1, 2, 2, 2]), 13: ([2, 2, 2, 2, 2]), 16: ([2, 2, 3, 3, 3]), 19: ([2, 2, 4, 4, 4]) } assert layers in vgg_spec.keys(), \ "supported layers are {} but input layer is {}".format(vgg_spec.keys(), layers) nums = vgg_spec[layers] conv1 = self.conv_block(input, 64, nums[0]) conv2 = self.conv_block(conv1, 128, nums[1]) conv3 = self.conv_block(conv2, 256, nums[2]) conv4 = self.conv_block(conv3, 512, nums[3]) conv5 = self.conv_block(conv4, 512, nums[4]) fc_dim = 4096 fc1 = fluid.layers.fc( input=conv5, size=fc_dim, act='relu', param_attr=fluid.param_attr.ParamAttr( initializer=fluid.initializer.Normal(scale=0.005)), bias_attr=fluid.param_attr.ParamAttr( initializer=fluid.initializer.Constant(value=0.1))) fc1 = fluid.layers.dropout(x=fc1, dropout_prob=0.5) fc2 = fluid.layers.fc( input=fc1, size=fc_dim, act='relu', param_attr=fluid.param_attr.ParamAttr( initializer=fluid.initializer.Normal(scale=0.005)), bias_attr=fluid.param_attr.ParamAttr( initializer=fluid.initializer.Constant(value=0.1))) fc2 = fluid.layers.dropout(x=fc2, dropout_prob=0.5) out = fluid.layers.fc( input=fc2, size=class_dim, act='softmax', param_attr=fluid.param_attr.ParamAttr( initializer=fluid.initializer.Normal(scale=0.005)), bias_attr=fluid.param_attr.ParamAttr( initializer=fluid.initializer.Constant(value=0.1))) return out def conv_block(self, input, num_filter, groups): conv = input for i in range(groups): if i == groups - 1: act = None else: act = 'relu' conv = fluid.layers.conv2d( input=conv, num_filters=num_filter, filter_size=3, stride=1, padding=1, act=act, param_attr=fluid.param_attr.ParamAttr( initializer=fluid.initializer.Normal(scale=0.01)), bias_attr=fluid.param_attr.ParamAttr( initializer=fluid.initializer.Constant(value=0.0))) conv = fluid.layers.batch_norm(input=conv, act='relu') return fluid.layers.pool2d(input=conv, pool_size=2, pool_type='max', pool_stride=2)
如下是一些工具函數, 例如日誌處理, 圖片加強處理等等.
In[5]
# 初始化日誌 def init_log_config(): global logger logger = logging.getLogger() logger.setLevel(logging.INFO) log_path = os.path.join(os.getcwd(), 'logs') if not os.path.exists(log_path): os.makedirs(log_path) log_name = os.path.join(log_path, 'train.log') fh = logging.FileHandler(log_name, mode='w') fh.setLevel(logging.DEBUG) formatter = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s") fh.setFormatter(formatter) logger.addHandler(fh) # 簡單的圖像加強函數 def resize_img(img, target_size): percent_h = float(target_size[1]) / img.size[1] percent_w = float(target_size[2]) / img.size[0] percent = min(percent_h, percent_w) resized_width = int(round(img.size[0] * percent)) resized_height = int(round(img.size[1] * percent)) w_off = (target_size[1] - resized_width) / 2 h_off = (target_size[2] - resized_height) / 2 img = img.resize((resized_width, resized_height), Image.LANCZOS) array = np.ndarray((target_size[1], target_size[2], target_size[0]), np.uint8) array[:, :, 0] = 127.5 array[:, :, 1] = 127.5 array[:, :, 2] = 127.5 ret = Image.fromarray(array) ret.paste(img, (int(w_off), int(h_off))) return ret def random_brightness(img): prob = np.random.uniform(0, 1) if prob < train_parameters['image_distort_strategy']['brightness_prob']: brightness_delta = train_parameters['image_distort_strategy']['brightness_delta'] delta = np.random.uniform(-brightness_delta, brightness_delta) + 1 img = ImageEnhance.Brightness(img).enhance(delta) return img def random_contrast(img): prob = np.random.uniform(0, 1) if prob < train_parameters['image_distort_strategy']['contrast_prob']: contrast_delta = train_parameters['image_distort_strategy']['contrast_delta'] delta = np.random.uniform(-contrast_delta, contrast_delta) + 1 img = ImageEnhance.Contrast(img).enhance(delta) return img def random_saturation(img): prob = np.random.uniform(0, 1) if prob < train_parameters['image_distort_strategy']['saturation_prob']: saturation_delta = train_parameters['image_distort_strategy']['saturation_delta'] delta = np.random.uniform(-saturation_delta, saturation_delta) + 1 img = ImageEnhance.Color(img).enhance(delta) return img def random_hue(img): prob = np.random.uniform(0, 1) if prob < train_parameters['image_distort_strategy']['hue_prob']: hue_delta = train_parameters['image_distort_strategy']['hue_delta'] delta = np.random.uniform(-hue_delta, hue_delta) img_hsv = np.array(img.convert('HSV')) img_hsv[:, :, 0] = img_hsv[:, :, 0] + delta img = Image.fromarray(img_hsv, mode='HSV').convert('RGB') return img def distort_image(img): prob = np.random.uniform(0, 1) # Apply different distort order if prob < 0.25: img = random_brightness(img) img = random_contrast(img) img = random_saturation(img) img = random_hue(img) elif prob < 0.5: img = random_brightness(img) img = random_saturation(img) img = random_hue(img) img = random_contrast(img) return img # 自定義數據讀取器 def custom_image_reader(file_list, data_dir, mode): with codecs.open(file_list) as flist: lines = [line.strip() for line in flist] train_parameters['image_count'] = len(lines) np.random.shuffle(lines) label_set = set() for line in lines: img_path, label = line.split() label_set.add(label) train_parameters['class_dim'] = len(label_set) print("class dim:{0} image count:{1}".format(train_parameters['class_dim'], train_parameters['image_count'])) def reader(): for line in lines: if mode == 'train' or mode == 'val': img_path, label = line.split() img_path = os.path.join(data_dir, img_path) img = Image.open(img_path) try: if img.mode != 'RGB': img = img.convert('RGB') if train_parameters['image_distort_strategy']['need_distort'] == True: img = distort_image(img) mirror = int(np.random.uniform(0, 2)) if mirror == 1: img = img.transpose(Image.FLIP_LEFT_RIGHT) img = resize_img(img, train_parameters['input_size']) # HWC--->CHW && normalized img = np.array(img).astype('float32') img -= train_parameters['mean_rgb'] img = img.transpose((2, 0, 1)) # HWC to CHW img *= 0.007843 yield img, int(label) except Exception as e: pass elif mode == 'test': img_path = os.path.join(data_dir, line) if img.mode != 'RGB': img = img.convert('RGB') img = resize_img(img, train_parameters['input_size']) yield img return reader # 優化器 def optimizer_momentum_setting(): """ 階梯型的學習率適合比較大規模的訓練數據 """ learning_strategy = train_parameters['momentum_strategy'] batch_size = train_parameters["train_batch_size"] iters = train_parameters["image_count"] // batch_size lr = learning_strategy['learning_rate'] boundaries = [i * iters for i in learning_strategy["lr_epochs"]] values = [i * lr for i in learning_strategy["lr_decay"]] learning_rate = fluid.layers.piecewise_decay(boundaries, values) optimizer = fluid.optimizer.MomentumOptimizer(learning_rate=learning_rate, momentum=0.9) return optimizer def optimizer_rms_setting(): """ 階梯型的學習率適合比較大規模的訓練數據 """ batch_size = train_parameters["train_batch_size"] iters = train_parameters["image_count"] // batch_size learning_strategy = train_parameters['rsm_strategy'] lr = learning_strategy['learning_rate'] boundaries = [i * iters for i in learning_strategy["lr_epochs"]] values = [i * lr for i in learning_strategy["lr_decay"]] optimizer = fluid.optimizer.RMSProp( learning_rate=fluid.layers.piecewise_decay(boundaries, values), regularization=fluid.regularizer.L2Decay(0.00005)) return optimizer def optimizer_sgd_setting(): """ loss降低相對較慢,可是最終效果不錯,階梯型的學習率適合比較大規模的訓練數據 """ learning_strategy = train_parameters['momentum_strategy'] batch_size = train_parameters["train_batch_size"] iters = train_parameters["image_count"] // batch_size lr = learning_strategy['learning_rate'] boundaries = [i * iters for i in learning_strategy["lr_epochs"]] values = [i * lr for i in learning_strategy["lr_decay"]] learning_rate = fluid.layers.piecewise_decay(boundaries, values) optimizer = fluid.optimizer.SGD(learning_rate=learning_rate) return optimizer def optimizer_adam_setting(): """ 可以比較快速的下降 loss,可是相對後期乏力。對於小規模的數據,比較適合 """ optimizer = fluid.optimizer.Adam(learning_rate=0.01) return optimizer # 保存模型 def save_model(base_dir, base_name, feed_var_list, target_var_list, program, exe): fluid.io.save_persistables(dirname=base_dir, filename=base_name + '-retrain', main_program=program, executor=exe) fluid.io.save_inference_model(dirname=base_dir, params_filename=base_name + '-params', model_filename=base_name + '-model', feeded_var_names=feed_var_list, target_vars=target_var_list, main_program=program, executor=exe)
設置讀取訓練數據,組裝模型,檢驗訓練精度。在代碼中能夠更換想要的模型
In[6]
init_log_config() train_prog = fluid.Program() train_startup = fluid.Program() print("create prog success") logger.info("create prog success") logger.info("train config:%s", train_parameters) logger.info("build input custom reader and data feeder") file_list = os.path.join(train_parameters['data_dir'], "label.txt") mode = train_parameters['mode'] batch_reader = paddle.batch(custom_image_reader(file_list, train_parameters['data_dir'], mode), batch_size=train_parameters['train_batch_size'], drop_last=True) place = fluid.CUDAPlace(0) if train_parameters['use_gpu'] else fluid.CPUPlace() img = fluid.layers.data(name='img', shape=train_parameters['input_size'], dtype='float32') label = fluid.layers.data(name='label', shape=[1], dtype='int64') feeder = fluid.DataFeeder(feed_list=[img, label], place=place) logger.info("build newwork") # ~~~~~~替換模型在此~~~~~~ # model = ResNet(layers=50) # model = VGGNet(layers=16) model = MobileNet() out = model.net(input=img, class_dim=train_parameters['class_dim']) cost = fluid.layers.cross_entropy(out, label) avg_cost = fluid.layers.mean(x=cost) acc_top1 = fluid.layers.accuracy(input=out, label=label, k=1) # optimizer = optimizer_rms_setting() optimizer = optimizer_momentum_setting() # optimizer = optimizer_sgd_setting() # optimizer = optimizer_adam_setting() optimizer.minimize(avg_cost) exe = fluid.Executor(place)
2019-04-24 16:09:22,866 - INFO - create prog success 2019-04-24 16:09:22,867 - INFO - train config:{'input_size': [3, 224, 224], 'class_dim': -1, 'data_dir': 'data/data62/train', 'save_model_dir': './classify-model', 'mode': 'train', 'num_epochs': 120, 'image_count': -1, 'train_batch_size': 50, 'mean_rgb': [127.5, 127.5, 127.5], 'use_gpu': True, 'image_distort_strategy': {'need_distort': True, 'expand_prob': 0.5, 'expand_max_ratio': 4, 'hue_prob': 0.5, 'hue_delta': 18, 'contrast_prob': 0.5, 'contrast_delta': 0.5, 'saturation_prob': 0.5, 'saturation_delta': 0.5, 'brightness_prob': 0.5, 'brightness_delta': 0.125}, 'rsm_strategy': {'learning_rate': 0.02, 'lr_epochs': [20, 40, 60, 80, 100], 'lr_decay': [1, 0.5, 0.25, 0.1, 0.01, 0.002]}, 'momentum_strategy': {'learning_rate': 0.005, 'lr_epochs': [20, 40, 60, 80, 100], 'lr_decay': [1, 0.5, 0.25, 0.1, 0.01, 0.002]}} 2019-04-24 16:09:22,867 - INFO - build input custom reader and data feeder 2019-04-24 16:09:22,881 - INFO - build newwork
create prog success class dim:2 image count:23202
模型訓練主體訓練,有必定提早中止策略。煉丹開始! 注意觀察loss的變化,而後開始不一樣任務的不一樣調參吧~
In[5]
main_program = fluid.default_main_program() exe.run(fluid.default_startup_program()) # 若是有訓練過的參數,能夠經過打開這句話來加載接着訓練 # fluid.io.load_persistables(dirname=train_parameters['save_model_dir'], filename=model.name() + '-retrain', main_program=main_program, executor=exe) train_fetch_list = [avg_cost.name, acc_top1.name, out.name] successive_count = 0 stop_train = False total_batch_count = 0 for pass_id in range(train_parameters["num_epochs"]): logger.info("current pass: %d, start read image", pass_id) batch_id = 0 for step_id, data in enumerate(batch_reader()): t1 = time.time() loss, acc1, pred_ot = exe.run(main_program, feed=feeder.feed(data), fetch_list=train_fetch_list) t2 = time.time() batch_id += 1 total_batch_count += 1 period = t2 - t1 loss = np.mean(np.array(loss)) acc1 = np.mean(np.array(acc1)) if batch_id % 10 == 0: print("Pass {0}, trainbatch {1}, loss {2}, acc1 {3}, time {4}".format(pass_id, batch_id, loss, acc1, "%2.2f sec" % period)) logger.info("Pass {0}, trainbatch {1}, loss {2}, acc1 {3}, time {4}".format(pass_id, batch_id, loss, acc1, "%2.2f sec" % period)) if acc1 >= 0.93: successive_count += 1 fluid.io.save_inference_model(dirname=train_parameters['save_model_dir'], params_filename=model.name() + '-params', model_filename=model.name() + '-model', feeded_var_names=['img'], target_vars=[out], main_program=main_program, executor=exe) if successive_count >= 5: logger.info("end training") print("end training") stop_train = True break else: successive_count = 0 if total_batch_count % 400 == 0: logger.info("temp save {0} batch train result".format(total_batch_count)) print("temp save {0} batch train result".format(total_batch_count)) fluid.io.save_persistables(dirname=train_parameters['save_model_dir'], filename=model.name() + '-retrain', main_program=main_program, executor=exe) if stop_train: break save_model(train_parameters['save_model_dir'], model.name() + '-final', ['img'], [out], main_program, exe)
2019-04-24 16:09:26,127 - INFO - current pass: 0, start read image 2019-04-24 16:09:33,745 - INFO - Pass 0, trainbatch 10, loss 0.6780937910079956, acc1 0.6200000047683716, time 0.08 sec
Pass 0, trainbatch 10, loss 0.6780937910079956, acc1 0.6200000047683716, time 0.08 sec
將單個模型參數文件拆分紅多個模型參數文件,以便後面的操做
In[20]
# -*- coding: UTF-8 -*- """ 模型轉換工具,將已經保存的多參數文件合併爲單參數文件 """ import os import paddle import paddle.fluid as fluid def muti_to_single(base_name, feeeze_path, out_path): """ param base_name: 模型的基本名字 param feeeze_path: 多文件預測模型所保存的目錄 param out_path: 合併後文件的輸出路徑 """ place = fluid.CPUPlace() exe = fluid.Executor(place) [inference_program, feed_target_names, fetch_targets] = paddle.fluid.io.load_inference_model(feeeze_path, exe) fluid.io.save_inference_model(dirname=out_path, params_filename=base_name + '-params', model_filename=base_name + '-model', feeded_var_names=feed_target_names, target_vars=fetch_targets, main_program=inference_program, executor=exe) def single_to_muti(base_name, feeeze_path, out_path): """ param base_name: 模型的基本名字 param feeeze_path: 多文件預測模型所保存的目錄 param out_path: 合併後文件的輸出路徑 """ place = fluid.CPUPlace() exe = fluid.Executor(place) [inference_program, feed_target_names, fetch_targets] = paddle.fluid.io.load_inference_model(feeeze_path, exe, params_filename=base_name + '-params', model_filename=base_name + '-model', ) fluid.io.save_inference_model(dirname=out_path, feeded_var_names=feed_target_names, target_vars=fetch_targets, main_program=inference_program, executor=exe) if __name__ == '__main__': # muti_to_single('yolov3', 'freeze', '.') single_to_muti('mobile-net', 'classify-model', 'freeze-model')
訓練完成以後,咱們可使用訓練好的模型來進行預測,看看貓貓的圖片是否能預測類別1,狗狗的圖片是類別0
In[14]
from __future__ import absolute_import from __future__ import division from __future__ import print_function import scipy.io as sio import os import numpy as np import random import time import six import sys import functools import time import math import paddle import paddle.fluid as fluid import paddle.dataset.flowers as flowers import argparse import functools import subprocess import distutils.util from paddle.fluid import core from paddle.fluid.param_attr import ParamAttr from PIL import Image, ImageEnhance import logging target_size = [3, 224, 224] mean_rgb = [127.5, 127.5, 127.5] place = fluid.CPUPlace() exe = fluid.Executor(place) path = "classify-model" [inference_program, feed_target_names, fetch_targets] = fluid.io.load_inference_model(dirname=path, params_filename ='mobile-net-params', model_filename='mobile-net-model', executor=exe) # print(fetch_targets) def resize_img(img, target_size): percent_h = float(target_size[1]) / img.size[1] percent_w = float(target_size[2]) / img.size[0] percent = min(percent_h, percent_w) resized_width = int(round(img.size[0] * percent)) resized_height = int(round(img.size[1] * percent)) img = img.resize((resized_width, resized_height), Image.ANTIALIAS) w_off = (target_size[1] - resized_width) / 2 h_off = (target_size[2] - resized_height) / 2 array = np.ndarray((target_size[1], target_size[2], target_size[0]), np.uint8) array[:, :, 0] = 127.5 array[:, :, 1] = 127.5 array[:, :, 2] = 127.5 ret = Image.fromarray(array) ret.paste(img, (int(w_off), int(h_off))) return ret def read_image(img_path): img = Image.open(img_path) if img.mode != 'RGB': img = img.convert('RGB') img = resize_img(img, target_size) img = np.array(img).astype('float32') img -= mean_rgb img = img.transpose((2, 0, 1)) # HWC to CHW img *= 0.007843 img = img[np.newaxis,:] return img def infer(image_path): tensor_img = read_image(image_path) t1 = time.time() label = exe.run(inference_program, feed={feed_target_names[0]: tensor_img}, fetch_list=fetch_targets) period = time.time() - t1 print("predict result:{0} cost time:{1}".format(label, "%2.2f sec" % period)) return period, np.argmax(label) # image_path = sys.argv[1] # 1--4是狗狗的圖片,5--11是貓貓的圖片 image_path = 'data/data62/test/723.jpg' # 這是一張狗狗的照片 period, result = infer(image_path) print(result)
普通的模型並不能很好地運行在開發板等特定硬件上, 爲了在特定硬件上部署, 須要藉助一些工具.
本次演示的是Paddle派轉換工具.
首先先拉取並解壓模型轉換工具:
In[ ]
!mkdir /home/aistudio/work/ncc !wget "https://platform.bj.bcebos.com/sdk%2Fncc-linux-x86_64.tar.gz" -O ncc-linux-x86_64.tar.gz !tar -zxvf ncc-linux-x86_64.tar.gz -C /home/aistudio/work/ncc
而後進行模型壓縮. 咱們須要進行量化。爲了保證量化後的精度, 須要使用訓練圖片調整模型。
In[18]
import codecs import shutil import os target_dir = 'work/images/' if not os.path.exists(target_dir): os.makedirs(target_dir) for i in range(200, 300): source_path = os.path.join('data/data62/train/', str(i) + '.jpg') target_path = os.path.join(target_dir, str(i) + '.jpg') if os.path.exists(source_path): shutil.copy(source_path, target_path)
最後進行進行模型轉換, 而後將模型進行下載, 就能夠部署到本身的Paddle派開發板上了
In[ ]
!/home/aistudio/work/ncc/ncc -i paddle -o k210model --dataset work/images/ freeze-model mobilenet.kmodel
至此演示所有完成. 若是有問題, 能夠郵件至 aistudio@baidu.com諮詢
>> 訪問 PaddlePaddle 官網,瞭解更多相關內容。