查看: 5108|回复: 0

[分享] eIQ Toolkit上手指南(三)

[复制链接]
  • TA的每日心情
    开心
    2024-3-26 15:16
  • 签到天数: 266 天

    [LV.8]以坛为家I

    3298

    主题

    6545

    帖子

    0

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    32003
    最后登录
    2024-4-9
    发表于 2022-1-20 12:56:29 | 显示全部楼层 |阅读模式
    相信看过上期文章的朋友们,已经知道我们这次的主题了,如何在eIQ Portal工具中批量导入我们的自定义数据集以及自定义模型。

    导入自定义数据集
    首先是导入数据集,开始遇到这个问题的时候,小编我也是一脸茫然,并不知道从何下手。就在小编踏破铁鞋之际,一缕阳光,照进了小编的世界。小编发现,eIQ Portal支持通过编写Python脚本形式进行数据集的导入,并生成对应的工程文件,而且已经很贴心的提供了一个参考例程,先来看看怎么运行它:
    1、打开eIQ Portal点击“COMMAND LINE”
    2、将目录切换到<eIQ_Toolkit_install_dir>/workspace文件夹
    3、安装tqdm库,运行本文件夹下的CIFAR_uploader脚本:
       a、python -m pip install tqdm
       b、python -m CIFAR_uploader

    当脚本运行完毕,CIFAR-10数据集就会被加载到我们的工程文件,并保存为cifar10.deepview到当前目录。
    我们来看看具体是怎么做的,实际干活的脚本有两个,其中一个是importer.py,可以把它当作一个辅助工具,帮助我们导入并制作工程,直接引用即可,无需分析;另一个是CIFAR_uploader.py,这个是主程序入口,我们来详细分析它,主要有如下几个关键部分:
    1. 声明数据加载器,指定工程名字以及路径:
    1. datastore = DataStoreWrapper(datastore='http://127.0.0.1:10812/')
    2.   datastore.create_project(project_name='cifar10.deepview', path='E:\\DATASETS'
    复制代码
    2. 指定数据标签名,加载数据
    1. class_names = ["airplane","automobile","bird","cat","deer","dog","frog","horse","ship","truck"]
    2.   (x_train, y_train), (x_test, y_test) = tf.keras.datasets.cifar10.load_data()
    复制代码
    这里要特殊说明一下,class_names需要根据实际应用场景进行指定。

    比较特殊的是数据加载部分,这里我们是直接加载的keras数据集。但是,往往在实际使用中,keras所自带的数据集往往不能够满足我们的要求(仅内建了cifar10,lenet以及mnistfashion数据集)。这样一来,我们就需要自己制作数据集,当然了,熟悉numpy的伙伴们有福了。我们知道keras的load_data函数实际上返回的就是numpy数组形式的数据集,那我们在使用时,可以自行制作numpy形式的数据集进行替换即可。


    3. 数据集切片,如果你仅仅想要导入一部分数据集,当然,如果想加载全部数据,也可以跳过这一步骤:
    1. x_train = x_train[:1000]
    2.    y_train = y_train[:1000]
    3.    x_test = x_test[:500]
    4.    y_test = y_test[:500]
    复制代码
    4. 到了最关键的一步,将我们的数据集插入我们的工程中,此处我们还可以自行指定图像大小。当然,我们的eIQ Portal可以接受任意尺度的图像输入,在训练时候可以进行动态调整:
    1. new_dimension = (128, 128)
    2.   for i in tqdm.tqdm(range(x_train.shape[0])):
    3.      datastore.upload_image(x_train[i], class_names[y_train[i][0]], new_dimension)
    4.   for i in tqdm.tqdm(range(x_test.shape[0])):
    5.      datastore.upload_image(x_test[i], class_names[y_test[i][0]], new_dimension)
    复制代码
    5. 小贴士,讲到这儿,小编还要多和大家说一句,我们这里使用的是网上的开源数据集,其特色就是每张图都有一个对应的标号形式(在class_names中的标号)的标签数据,也就是这里的y_train/y_test,来指代其类别。


    当我们使用自己的图片时,就需要自己来为数据集一张张地进行标注了,并制作相应的y_train/y_test数组。
    这样,我们就将我们的数据集导入到了工程文件中。

    自定义模型
    模型的添加依旧是依靠Python脚本的形式,目前支持两种类型模型的添加,classification(分类模型)以及detection(目标检测模型)。

    实现方案非常简单,我们只需要将模型脚本文件,根据其应用类型,放置到<eIQ_Toolkit_install_dir>/plugins/下对应的classification或是detection中即可。

    我们来看看怎么实现一个模型脚本文件:

    1. 导入依赖库
    1. from deepview.trainer.extensions import interfaces
    2. import tensorflow as tf
    3. import os

    4. def get_plugin():
    5.   return cifar10
    复制代码
    2.定义模型,这里我们需要定义一个类,并继承interfaces.ImageClassificationInterface,类名就是我们给模型起的名字,我们假设其为cifar10:
    1. class cifar10(interfaces.ImageClassificationInterface):
    复制代码
    3. 在第2步中,我们已经定义好了我们的模型类,接下来我们要为我们的模型类定义其成员函数,而这些是我们模型脚本文件中的重点:
    上面我们留了一个比较特殊的函数get_exposed_parameters,这个函数用于添加一些控制字参数,返回一个字典列表,而我们所定义的变量可以显示在eIQ Portal的MODEL PARAMETERS选项栏中,例如我们定义了:
    1.    def get_exposed_parameters(self):
    2.         return [
    3.             {
    4.                 "name": "Optimizer",
    5.                 "key": "optimizer",
    6.                 "default": "Adam",
    7.                 "values": ["SGD", "Adam", "RMSprop", "Nadam", "Adadelta", "Adagrad", "Adamax"],
    8.                 "description": "Model optimizer"
    9.             }
    10.         ]
    复制代码
    这样,我们就可以在eIQ Portal中看到我们所定义的变量及其值:
    14.png
    模型的构建
    关于模型的构建部分,我们知道需要通过get_model函数返回一个模型变量,我们来具体看下这个函数的函数声明:
    1. def get_model(self, input_shape, num_classes=10, weights='local', named_params={})
    复制代码
    实际使用到的参数,有4个:
    1、input_shape: 传入的模型输入尺寸
    2、num_classed: 模型分类数量,即模型输出尺寸
    3、weights: 模型权重获取方式,可以是网络下载预训练模型/随机或是本地存储的模型权重
    4、named_params:由get_exposed_parameters所定义的变量,通过named_params.get(key, default_value),方法获取对应值,其中通过get_exposed_parameter所定义的变量,如果没有定义某个key值,那么就返回default_value


    前文也说过,返回的模型格式是keras模型格式,既可以是以Sequential形式构建的,也可以是以function即函数式方式构建的,我们以一个3层卷积+1层全连接的模型为例,简单介绍下如何进行模型的搭建:


    1. 函数式,顾名思义就是以类似函数调用的方式搭建模型:
    1. def cifar10_base():
    2.     _in = Input(shape=(32,32,3))
    3.     x = Conv2D(32, (3,3), padding="same")(_in)
    4.     x = BatchNormalization()(x)
    5.     x = Activation("relu")(x)
    6.     x = MaxPooling2D(2,2)(x)

    7.     x = Conv2D(64, (3,3), padding="same")(x)
    8.     x = BatchNormalization()(x)
    9.     x = Activation("relu")(x)
    10.     x = MaxPooling2D(2,2)(x)

    11.     x = Conv2D(128, (3,3), padding="same")(x)
    12.     x = BatchNormalization()(x)
    13.     x = Activation("relu")(x)
    14.     x = MaxPooling2D(2,2)(x)

    15.     x = Flatten()(x)

    16.     x = Dense(10)(x)
    17.     x = Activation("softmax")(x)

    18.     return Model(_in, x)
    复制代码
    2. Sequential式,这种方式比较简单,但是缺点是,只能构建串行网络,不如函数式灵活:
    1. def cifar10_base():
    2.     model = Sequential()
    3.     model.add(Conv2D(32, (3,3), padding="same", input_shape=(32, 32, 3)))
    4.     model.add(BatchNormalization())
    5.     model.add(Activation("relu"))
    6.     model.add(MaxPooling2D(2,2))

    7.     model.add(Conv2D(64, (3,3), padding="same"))
    8.     model.add(BatchNormalization())
    9.     model.add(Activation("relu"))
    10.     model.add(MaxPooling2D(2,2))

    11.     model.add(Conv2D(128, (3,3), padding="same"))
    12.     model.add(BatchNormalization())
    13.     model.add(Activation("relu"))
    14.     model.add(MaxPooling2D(2,2))

    15.     model.add(Flatten())

    16.     model.add(Dense(10))
    17.     model.add(Activation("softmax"))

    18.     return model
    复制代码
    我们来看看实际的代码样子,实际使用中,根据需要自行修改即可:
    1. def get_plugin():
    2.     return cifar10
    3.    
    4. class cifar10(interfaces.ImageClassificationInterface):

    5.     def get_name(self):
    6.         return "cifar10"

    7.     def is_base(self):
    8.         return True

    9.     def get_model(self, input_shape, num_classes=10, weights='local', named_params={}):

    10.         with open("./workspace/model_log.txt", "w") as f:
    11.             if not (weights in {'local', None} or os.path.exists(weights)):
    12.                 raise ValueError(
    13.                     "The 'weights' argument must be None, a valid file, or 'imagenet'")

    14.             weights_file = weights if weights not in {'local', None} else r".\plugins\classification\image\cifar10\cifar10_weights.hdf5"

    15.             if(not weights): weights_file = None


    16.             model = cifar10_base()
    17.             self.num_params = model.count_params()

    18.             if weights_file:
    19.                 # carefully using the by_name=True, skip_mismatch=True, the diferent version of the tf will cause that the
    20.                 # name of each node will not the same one.
    21.                 model.load_weights(weights_file)

    22.             f.write("weights from : %s\n"%weights)
    23.             f.write("total params : %d \n"%self.num_params)
    24.             model.summary(print_fn = lambda x:f.write(x + "\n"))
    25.             f.close()

    26.             return model


    27.     def get_task(self):
    28.         return "classification"

    29.     def get_exposed_parameters(self):
    30.         return [
    31.             {
    32.                 "name": "Optimizer",
    33.                 "key": "optimizer",
    34.                 "default": "Adam",
    35.                 "values": ["SGD", "Adam", "RMSprop", "Nadam", "Adadelta", "Adagrad", "Adamax"],
    36.                 "description": "Model optimizer"
    37.             }
    38.         ]

    39.     def get_preprocess_function(self):
    40.         return lambda x: x / 128.0 - 1

    41.     def get_losses(self):
    42.         return ["CategoricalCrossentropy"]

    43.     def get_optimizers(self):
    44.         return ["SGD"]

    45.     def get_metrics(self):
    46.         return ["CategoricalAccuracy"]

    47.     def get_allowed_dimensions(self):
    48.         return ["32"]

    49.     def get_pretrained_dimensions(self):
    50.         return [["32", 'local']]

    51.     def get_qat_support(self):
    52.         return [{
    53.             # Per-Channel Quantization
    54.             "supported": "true",
    55.             "types": ['uint8', 'int8', 'float32'],
    56.             "frameworks": ['Tensorflow', 'Converter']
    57.         }, {
    58.             # Per-Tensor Quantization
    59.             "supported": "true",
    60.             "types": ['uint8', 'int8', 'float32'],
    61.             "frameworks": ["Converter"]
    62.         }]

    63.     def get_ptq_support(self):
    64.         return [{
    65.             # Per-Channel Quantization
    66.             "supported": "true",
    67.             "types": ['uint8', 'int8', 'float32'],
    68.             "frameworks": ['Tensorflow', 'Converter']
    69.         }, {
    70.             # Per-Tensor Quantization
    71.             "supported": "true",
    72.             "types": ['uint8', 'int8', 'float32'],
    73.             "frameworks": ["Converter"]
    74.         }]
    复制代码
    这样一来,我们就定义好了我们的自定义模型,再次打开我们的eIQ Portal之后,即可看到我们新添加的模型:
    15.png
    点选之后,即可进入我们熟悉的界面进行模型的训练,验证,导出等,小编这里就不再给大家演示了,请小伙伴们自行体验:
    17.png
    至此,小编就给大家介绍完了如何添加自定义数据集并定义自定义模型,我们将把模型的部署留在下一期和大家分享,正所谓好东西要留在最后享用!我们下期见。




    相关阅读:
    eIQ Toolkit上手指南(一)
    eIQ Toolkit上手指南(二)
    恩智浦小课堂第二十九期—30分钟在MCU上跑通机器学习
    恩智浦相关的【软件大全】







    签到签到
    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /4 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2024-4-20 11:00 , Processed in 0.111218 second(s), 22 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表