文档首页 > > AI工程师用户指南> 训练管理> 自动化搜索作业> 示例:使用多元搜索

示例:使用多元搜索

分享
更新时间:2020/11/17 GMT+08:00

多元搜索是指在一次作业中同时完成数据增强、超参搜索和神经网络架构搜索(NAS)中两者或三者的搜索。

目前AutoSearch中,是以一种串行的方式来实现多元搜索。以自动数据增强+超参搜索+NAS搜索为例,搜得最优的数据增强策略,再带着最优的增强策略,搜得最优的学习率,最后使用最佳的增强策略、最优的学习率,继续搜索最优的结构。

场景

在限制以BatchSize=100,只训练5000步的情况下,在指定的数据增强策略、超参、类ResNet50结构的搜索空间内,在MNIST数据集上进行训练,寻找最合适的增强策略、学习率和网络结构。

针对上述场景,将会用到:

  • 一个支持如下3个功能的脚本。
    1. 解析增强策略
    2. 解析ResNet50的一种NAS编码
    3. 命令行解析学习率参数
  • 一个搜索自动增强策略的yaml配置。
  • 一个搜索学习率超参的yaml配置。
  • 一个搜索ResNet50结构的yaml配置。

将上述的3个yaml配置和代码组合使用,就能完成一次多元搜索。

样例代码

完整代码如下所示,在代码后面,介绍了代码中一些主要功能的详细配置说明。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 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
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
import argparse 
import time 
import os

import tensorflow as tf 
from autosearch.client.augment.offline_search.preprocessor_builder import ( 
    ImageClassificationTensorflowBuilder, 
) 
from autosearch.client.nas.backbone.resnet import ResNet50 
from tensorflow.examples.tutorials.mnist import input_data 

import autosearch 

parser = argparse.ArgumentParser() 
parser.add_argument( 
    "--max_steps", type=int, default=100, help="Number of steps to run trainer." 
) 
parser.add_argument("--data_url", type=str, default="MNIST_data") 

parser.add_argument( 
    "--learning_rate", 
    type=float, 
    default=0.01,   
    help="Number of steps to run trainer.", 
) 
FLAGS, unparsed = parser.parse_known_args() 

def train(): 
    if is_yundao():
        data_url = yundao_init(FLAGS.data_url)
    mnist = input_data.read_data_sets(data_url, one_hot=True) 
    with tf.Graph().as_default(): 
        sess = tf.InteractiveSession() 
        with tf.name_scope("input"): 
            x = tf.placeholder(tf.float32, [None, 784], name="x-input") 
            y_ = tf.placeholder(tf.int64, [None, 10], name="y-input") 
        x_aug = ImageClassificationTensorflowBuilder("offline")(x) 
        image_shaped_input = tf.reshape(x_aug, [-1, 28, 28, 1]) 
        y = ResNet50(image_shaped_input, include_top=True, mode="train") 
        with tf.name_scope("cross_entropy"): 
            y = tf.reduce_mean(y, [1, 2]) 
            y = tf.layers.dense(y, 10) 
            with tf.name_scope("total"): 
                cross_entropy = tf.losses.softmax_cross_entropy(y_, y) 

        with tf.name_scope("train"): 
            train_step = tf.train.AdamOptimizer(FLAGS.learning_rate).minimize(  # st2 
                cross_entropy 
            ) 

        with tf.name_scope("accuracy"): 
            with tf.name_scope("correct_prediction"): 
                correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1)) 
            with tf.name_scope("accuracy"): 
                accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) 
        tf.global_variables_initializer().run() 

        def feed_dict(train): 
            if train: 
                xs, ys = mnist.train.next_batch(100) 
            else: 
                xs, ys = mnist.test.images, mnist.test.labels 
            return {x: xs, y_: ys} 

        max_acc = 0 
        latencys = [] 
        for i in range(FLAGS.max_steps): 
            if i % 10 == 0:  # Record summaries and test-set accuracy 
                loss, acc = sess.run( 
                    [cross_entropy, accuracy], feed_dict=feed_dict(False) 
                ) 
                # print('loss at step %s: %s' % (i, loss)) 
                print("Accuracy at step %s: %s" % (i, acc)) 
                if acc > max_acc: 
                    max_acc = acc 
                # autosearch.reporter(loss=loss) 
                autosearch.reporter(mean_accuracy=acc) 
            else: 
                start = time.time() 
                loss, _ = sess.run( 
                    [cross_entropy, train_step], feed_dict=feed_dict(True) 
                ) 
                end = time.time() 
                if i % 10 != 1: 
                    latencys.append(end - start) 
        latency = sum(latencys) / len(latencys) 
        autosearch.reporter(mean_accuracy=max_acc, latency=latency) 
        sess.close()

def is_yundao():
    return True if os.path.exists("/home/work/user-job-dir") else False

def yundao_init(data_url):
    local_data_dir = "/cache/mnist"

    import moxing as mox

    mox.file.copy_parallel(data_url, local_data_dir)

    return local_data_dir
  • 在import语句中,import一个用于解析增强策略的模块和一个解析NAS结构编码的模块。
    1
    2
    3
    4
    # 用于解析增强策略,把策略的编码转换成实际的数据增强操作
    from autosearch.client.augment.offline_search.preprocessor_builder import ImageClassificationTensorflowBuilder
    # 用于解析NAS结构编码,会把'111-2111-211111-2111'这样的结构编码,翻译成tensorflow的网络结构
    from autosearch.client.nas.backbone.resnet import ResNet50
    

    代码中使用的两个预置decoder模块的详细解释参考使用预置解码器(Decoder)

  • 脚本提供了一些可配置的命令行参数。
    1
    2
    3
    4
    5
    6
    7
    8
    parser = argparse.ArgumentParser()
    parser.add_argument('--max_steps', type=int, default=100,
                        help='Number of steps to run trainer.')
    parser.add_argument('--data_dir', type=str, default="MNIST_data")
    
    parser.add_argument('--learning_rate', type=float, default=0.01,
                        help='Number of steps to run trainer.')
    FLAGS, unparsed = parser.parse_known_args()
    
  • 脚本定义了一个train函数。这里的函数名必须为train,AutoSearch会自动寻找脚本中的train函数。train函数中,生成一个前面import的ImageClassificationTensorflowBuilder来进行自动数据增强,以及使用前面import的一个ResNet50对象,来连接输入x与输出y。

    在代码中插入这两个对象以后,就能分别翻译传入的数据增强策略为数据增强操作,ResNet结构编码为TF的ResNet网络结构。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    def train():
        mnist = input_data.read_data_sets(FLAGS.data_dir, one_hot=True)
        with tf.Graph().as_default():
            sess = tf.InteractiveSession()
            with tf.name_scope('input'):
                x = tf.placeholder(tf.float32, [None, 784], name='x-input')
                y_ = tf.placeholder(tf.int64, [None, 10], name='y-input')
            # 
            x_aug = ImageClassificationTensorflowBuilder('offline')(x)
            image_shaped_input = tf.reshape(x_aug, [-1, 28, 28, 1])
            y = ResNet50(image_shaped_input, mode="train")
    
  • 需要在合适的时候,报告目前的训练结果,提供给AutoSearch记录当前的结果,以及由搜索算法来根据已有的结果来提出更好的尝试。
    autosearch.reporter(mean_accuracy=acc)

配置文件编写

  • 数据增强的yaml配置
    • 单次尝试的训练使用单机单卡来进行。
    • 使用了内置的image_classification_auto_augment,内置空间的详细信息请参见使用预置解码器(Decoder)
    • 搜索算法使用的是GridSearch,以mean_accuracy为指标,越大越好。
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    general:
      gpu_per_instance: 1
    
    search_space:
      - type: discrete
        params:
          - name: image_classification_auto_augment
            values: [['14-5-5', '14-5-5'],
                     ['14-6-6', '14-6-6'],
                     ['14-7-7', '14-7-7'],
                     ['14-8-8', '14-8-8'],
                     ['14-9-9', '14-9-9']
            ]
    
    search_algorithm:
      type: grid_search
      reward_attr: mean_accuracy
    
  • 搜索超参的yaml配置

    这个yaml用来搜索学习率,会尝试10的负1、负2、负3、负4、 负5次方这5个值。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    general:
      gpu_per_instance: 1
    
    search_space:
      - type: continuous
        params:
            - name: learning_rate
              start: -1
              stop: -5
              num: 5
              base: 10
    
    search_algorithm:
      type: grid_search
      reward_attr: mean_accuracy
    
  • 搜索NAS结构的yaml配置

    根据这个yaml,AutoSearch的GridSearch算法会遍历尝试提供的这11个结构。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    general:
      gpu_per_instance: 1
    
    search_space:
      - type: discrete
        params:
          - name: resnet50
            values: ["1-11111111-2111121111-211111",
                     "1-1112-1111111111121-11111112111",
                     "1-11111121-12-11111211",
                     "11-111112-112-11111211",
                     "1-1-111111112-11212",
                     "1-1-1-2112112",
                     "1-111211-1111112-21111111",
                     "1-1111111111-21112112-11111",
                     "1-111111111112-121111111121-11",
                     "11-211-121-11111121",
                     "111-2111-211111-211"
            ]
    
    search_algorithm:
      type: grid_search
      reward_attr: mean_accuracy
    scheduler:
      type: FIFOScheduler
    

样例代码的脚本和配置文件编写中的3个yaml组合起来,即可用来启动运行AutoSearch。

启动搜索作业

这个样例需要用到MNIST数据集,请参考示例:使用更优秀的网络结构替换原生ResNet50上传、配置数据集后,上传python脚本和yaml配置文件,根据创建自动化搜索作业章节启动搜索作业。配置多个yaml文件时,请配置多个yaml文件的完整路径,并以逗号分隔,例如,“obs://foo/bar.yaml,obs://bar/foo.yaml”

分享:

    相关文档

    相关产品

文档是否有解决您的问题?

提交成功!非常感谢您的反馈,我们会继续努力做到更好!
反馈提交失败,请稍后再试!

*必选

请至少选择或填写一项反馈信息

字符长度不能超过200

提交反馈 取消

如您有其它疑问,您也可以通过华为云社区问答频道来与我们联系探讨

智能客服提问云社区提问