在线时间4067 小时
UID3441752
注册时间2017-11-21
NXP金币759430
TA的每日心情 | 开心 2024-3-26 15:16 |
---|
签到天数: 266 天 [LV.8]以坛为家I
管理员
- 积分
- 32003
- 最后登录
- 2024-4-9
|
相信看过上期文章的朋友们,已经知道我们这次的主题了,如何在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. 声明数据加载器,指定工程名字以及路径:
- datastore = DataStoreWrapper(datastore='http://127.0.0.1:10812/')
- datastore.create_project(project_name='cifar10.deepview', path='E:\\DATASETS'
复制代码 2. 指定数据标签名,加载数据
- class_names = ["airplane","automobile","bird","cat","deer","dog","frog","horse","ship","truck"]
- (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. 数据集切片,如果你仅仅想要导入一部分数据集,当然,如果想加载全部数据,也可以跳过这一步骤:
- x_train = x_train[:1000]
- y_train = y_train[:1000]
- x_test = x_test[:500]
- y_test = y_test[:500]
复制代码 4. 到了最关键的一步,将我们的数据集插入我们的工程中,此处我们还可以自行指定图像大小。当然,我们的eIQ Portal可以接受任意尺度的图像输入,在训练时候可以进行动态调整:
- new_dimension = (128, 128)
- for i in tqdm.tqdm(range(x_train.shape[0])):
- datastore.upload_image(x_train[i], class_names[y_train[i][0]], new_dimension)
- for i in tqdm.tqdm(range(x_test.shape[0])):
- 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. 导入依赖库
- from deepview.trainer.extensions import interfaces
- import tensorflow as tf
- import os
- def get_plugin():
- return cifar10
复制代码 2.定义模型,这里我们需要定义一个类,并继承interfaces.ImageClassificationInterface,类名就是我们给模型起的名字,我们假设其为cifar10:
- class cifar10(interfaces.ImageClassificationInterface):
复制代码 3. 在第2步中,我们已经定义好了我们的模型类,接下来我们要为我们的模型类定义其成员函数,而这些是我们模型脚本文件中的重点:
上面我们留了一个比较特殊的函数get_exposed_parameters,这个函数用于添加一些控制字参数,返回一个字典列表,而我们所定义的变量可以显示在eIQ Portal的MODEL PARAMETERS选项栏中,例如我们定义了:
- def get_exposed_parameters(self):
- return [
- {
- "name": "Optimizer",
- "key": "optimizer",
- "default": "Adam",
- "values": ["SGD", "Adam", "RMSprop", "Nadam", "Adadelta", "Adagrad", "Adamax"],
- "description": "Model optimizer"
- }
- ]
复制代码 这样,我们就可以在eIQ Portal中看到我们所定义的变量及其值:
模型的构建
关于模型的构建部分,我们知道需要通过get_model函数返回一个模型变量,我们来具体看下这个函数的函数声明:
- 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. 函数式,顾名思义就是以类似函数调用的方式搭建模型:
- def cifar10_base():
- _in = Input(shape=(32,32,3))
- x = Conv2D(32, (3,3), padding="same")(_in)
- x = BatchNormalization()(x)
- x = Activation("relu")(x)
- x = MaxPooling2D(2,2)(x)
- x = Conv2D(64, (3,3), padding="same")(x)
- x = BatchNormalization()(x)
- x = Activation("relu")(x)
- x = MaxPooling2D(2,2)(x)
- x = Conv2D(128, (3,3), padding="same")(x)
- x = BatchNormalization()(x)
- x = Activation("relu")(x)
- x = MaxPooling2D(2,2)(x)
- x = Flatten()(x)
- x = Dense(10)(x)
- x = Activation("softmax")(x)
- return Model(_in, x)
复制代码 2. Sequential式,这种方式比较简单,但是缺点是,只能构建串行网络,不如函数式灵活:
- def cifar10_base():
- model = Sequential()
- model.add(Conv2D(32, (3,3), padding="same", input_shape=(32, 32, 3)))
- model.add(BatchNormalization())
- model.add(Activation("relu"))
- model.add(MaxPooling2D(2,2))
- model.add(Conv2D(64, (3,3), padding="same"))
- model.add(BatchNormalization())
- model.add(Activation("relu"))
- model.add(MaxPooling2D(2,2))
- model.add(Conv2D(128, (3,3), padding="same"))
- model.add(BatchNormalization())
- model.add(Activation("relu"))
- model.add(MaxPooling2D(2,2))
- model.add(Flatten())
- model.add(Dense(10))
- model.add(Activation("softmax"))
- return model
复制代码 我们来看看实际的代码样子,实际使用中,根据需要自行修改即可:
- def get_plugin():
- return cifar10
-
- class cifar10(interfaces.ImageClassificationInterface):
- def get_name(self):
- return "cifar10"
- def is_base(self):
- return True
- def get_model(self, input_shape, num_classes=10, weights='local', named_params={}):
- with open("./workspace/model_log.txt", "w") as f:
- if not (weights in {'local', None} or os.path.exists(weights)):
- raise ValueError(
- "The 'weights' argument must be None, a valid file, or 'imagenet'")
- weights_file = weights if weights not in {'local', None} else r".\plugins\classification\image\cifar10\cifar10_weights.hdf5"
- if(not weights): weights_file = None
- model = cifar10_base()
- self.num_params = model.count_params()
- if weights_file:
- # carefully using the by_name=True, skip_mismatch=True, the diferent version of the tf will cause that the
- # name of each node will not the same one.
- model.load_weights(weights_file)
- f.write("weights from : %s\n"%weights)
- f.write("total params : %d \n"%self.num_params)
- model.summary(print_fn = lambda x:f.write(x + "\n"))
- f.close()
- return model
- def get_task(self):
- return "classification"
- def get_exposed_parameters(self):
- return [
- {
- "name": "Optimizer",
- "key": "optimizer",
- "default": "Adam",
- "values": ["SGD", "Adam", "RMSprop", "Nadam", "Adadelta", "Adagrad", "Adamax"],
- "description": "Model optimizer"
- }
- ]
- def get_preprocess_function(self):
- return lambda x: x / 128.0 - 1
- def get_losses(self):
- return ["CategoricalCrossentropy"]
- def get_optimizers(self):
- return ["SGD"]
- def get_metrics(self):
- return ["CategoricalAccuracy"]
- def get_allowed_dimensions(self):
- return ["32"]
- def get_pretrained_dimensions(self):
- return [["32", 'local']]
- def get_qat_support(self):
- return [{
- # Per-Channel Quantization
- "supported": "true",
- "types": ['uint8', 'int8', 'float32'],
- "frameworks": ['Tensorflow', 'Converter']
- }, {
- # Per-Tensor Quantization
- "supported": "true",
- "types": ['uint8', 'int8', 'float32'],
- "frameworks": ["Converter"]
- }]
- def get_ptq_support(self):
- return [{
- # Per-Channel Quantization
- "supported": "true",
- "types": ['uint8', 'int8', 'float32'],
- "frameworks": ['Tensorflow', 'Converter']
- }, {
- # Per-Tensor Quantization
- "supported": "true",
- "types": ['uint8', 'int8', 'float32'],
- "frameworks": ["Converter"]
- }]
复制代码 这样一来,我们就定义好了我们的自定义模型,再次打开我们的eIQ Portal之后,即可看到我们新添加的模型:
点选之后,即可进入我们熟悉的界面进行模型的训练,验证,导出等,小编这里就不再给大家演示了,请小伙伴们自行体验:
至此,小编就给大家介绍完了如何添加自定义数据集并定义自定义模型,我们将把模型的部署留在下一期和大家分享,正所谓好东西要留在最后享用!我们下期见。
相关阅读:
eIQ Toolkit上手指南(一)
eIQ Toolkit上手指南(二)
恩智浦小课堂第二十九期—30分钟在MCU上跑通机器学习
恩智浦相关的【软件大全】
|
|