谁更胜一筹?——随机搜索 V.S. 网格搜索

简介: 谁更胜一筹?--随机搜索 V.S. 网格搜索 随机法和网格法都是常用的、有效的结构优化方法。那么它们两者当中谁更胜一筹呢?在本文中,作者通过有趣的地形搜索实验,找到了答案。

谁更胜一筹?--随机搜索 V.S. 网格搜索


在进行超参数优化工作时,我不断思考该使用随机搜索还是网格搜索呢?这时候,一个同事给我介绍了一篇由Bergstra和Bengio编写的随机搜索超参数优化论文(链接),文中认为在进行参数优化时随机搜索比网格搜索更有效。

 

我想通过测试来得到自己的答案,我的实验设置如下。给定空间为(1024,1024)的超参数空间,可由相同形状的矩阵表示。我们为寻找最佳超参数设置的预算是25个实验。因此,这将允许我们进行网格搜索,其中我们设置每个超参数有5个值的组合,或者在该空间中的25个随机搜索。此外,我设置了一个“批量”版本的随机搜索,执行5批次每批次5次随机搜索,优化调整每次批次后的搜索。生成多个这样的随机超参数空间后,计算两种随机搜索优于网格搜索的次数。


生成空间


这一步是生成随机2D超参数空间,例如某种地形。 我使用了Hill地形算法(链接)。 它是一个简单而优雅的算法。 代码如下:


 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

from __future__ import division, print_function

import numpy as np

import matplotlib.pyplot as plt

import matplotlib.cm as cm

import operator

%matplotlib inline

 

SIZE = 1024

NUM_ITERATIONS = 200

 

terrain = np.zeros((SIZE, SIZE), dtype="float")

mod_iter = NUM_ITERATIONS // 10

for iter in range(NUM_ITERATIONS):

    if iter % mod_iter == 0:

        print("iteration: {:d}".format(iter))

    r = int(np.random.uniform(0, 0.2 * SIZE))

    xc, yc = np.random.randint(0, SIZE - 1, 2)

    z = 0

    xmin, xmax = int(max(xc - r, 0)), int(min(xc + r, SIZE))

    ymin, ymax = int(max(yc - r, 0)), int(min(yc + r, SIZE))

    for x in range(xmin, xmax):

        for y in range(ymin, ymax):

            z = (r ** 2) - ((x - xc) ** 2 + (y - yc) ** 2)

            if z > 0:

                terrain[x, y] += z

print("total iterations: {:d}".format(iter))

# 标准化单元高度

zmin = np.min(terrain)

terrain -= zmin

zmax = np.max(terrain)

terrain /= zmax

# 通过z值平滑地形

terrain = np.power(terrain, 2)

# 乘以255以使地形以灰度表示

terrain = terrain * 255

terrain = terrain.astype("uint8")

 


从上面代码生成的一个可能的地形如下所示。 我还为它生成了一个等高线图。

1

2

3

4

5

6

7

8

9

plt.title("terrain")

image = plt.imshow(terrain, cmap="gray")

plt.ylim(max(plt.ylim()), min(plt.ylim()))

plt.colorbar(image, shrink=0.8)

 

plt.title("contours")

contour = plt.contour(terrain, linewidths=2)

plt.ylim(max(plt.ylim()), min(plt.ylim()))

plt.colorbar(contour, shrink=0.8, extend='both')



ec9b84f1f4e7d9dcadf8a30529957fcc6e61caf9


网格搜索
 

如您所见,地形只是一个形状矩阵(1024,1024)。 由于我们的预算是25个实验,我们将在这个地形上进行一次5x5的网格搜索。 意即在x和y轴上选择5个等距点,并读取这些(x,y)位置处的地形矩阵值。 执行此操作的代码如下所示。 在轮廓图上的点的最佳值以蓝色标示。


 

 1

 2

 3

 4

 5

 6

 7

 8

 9

10

11

12

13

14

15

16

17

18

19

20

21

# 执行 (5x5)网格搜索

results = []

for x in np.linspace(0, SIZE-1, 5):

    for y in np.linspace(0, SIZE-1, 5):

        xi, yi = int(x), int(y)

        results.append([xi, yi, terrain[xi, yi]])

 

best_xyz = [r for r in sorted(results, key=operator.itemgetter(2))][0]

grid_best = best_xyz[2]

print(best_xyz)

 

xvals = [r[0] for r in results]

yvals = [r[1] for r in results]

 

plt.title("grid search")

contour = plt.contour(terrain, linewidths=2)

plt.ylim(max(plt.ylim()), min(plt.ylim()))

plt.scatter(xvals, yvals, color="b", marker="o")

plt.scatter([best_xyz[0]], [best_xyz[1]], color='b', s=200, facecolors='none', edgecolors='b')

plt.ylim(max(plt.ylim()), min(plt.ylim()))

plt.colorbar(contour)

 161b749ccf6251ec61dcb8e0b43c97b68f1d3726


网格搜索中最优点坐标为(767,767),值为109。


随机搜索


接下来进行实验的是纯随机搜索。由于实验预设为25个,所以这里仅随机生成x值和y值,然后在这些点中搜索地形矩阵值。



1

 2

 3

 4

 5

 6

 7

 8

 9

10

11

12

13

14

15

16

17

18

19

20

21

# 进行随机搜索

results = []

xvals, yvals, zvals = [], [], []

for i in range(25):

    x = np.random.randint(0, SIZE, 1)[0]

    y = np.random.randint(0, SIZE, 1)[0]

    results.append((x, y, terrain[x, y]))

 

best_xyz = sorted(results, key=operator.itemgetter(2))[0]

rand_best = best_xyz[2]

print(best_xyz)

 

xvals = [r[0] for r in results]

yvals = [r[1] for r in results]

 

plt.title("random search")

contour = plt.contour(terrain, linewidths=2)

plt.ylim(max(plt.ylim()), min(plt.ylim()))

plt.scatter(xvals, yvals, color="b", marker="o")

plt.scatter([best_xyz[0]], [best_xyz[1]], color='b', s=200, facecolors='none', edgecolors='b')

plt.colorbar(contour)

 

f60df8ee3c0c623e625f47f4a66507b4541ef63f

在该测试中,随机搜索做得更好一些,找到坐标为(663,618)值为103的点。


批量随机搜索


在这种方法中,我决定将我的25个实验预算分成5批,每批5个实验。 查找(x,y)值在每个批次内是随机的。 同时,在每个批次结束时,优胜者会被挑出来进行特殊处理。 采用对象不是在空间中任何地方生成的点,而是在这些点周围绘制一个窗口,并且仅从这些空间进行采样。 在每次迭代时,窗口会进行几何收缩。我试图寻找到目前为止找到的最优点的邻域中的点,希望这个搜索将产生更多的最优点。 同时,我保留剩余的实验探索空间,希望我可能找到另一个最佳点。 其代码如下所示:

 

 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

def cooling_schedule(n, k):

    """ 每次运行时减少窗口的大小

        n – 批次数目

        k – 当前批次的索引号

        返回 乘数(0..1) 的大小

    """

    return (n - k) / n

 

results, winners = [], []

for bid in range(5):

    print("Batch #: {:d}".format(bid), end="")

   

    # 计算窗口大小

    window_size = int(0.25 * cooling_schedule(5, bid) * SIZE)

 

    # 计算出优胜者并把其值加入结果中

    # 只保持最优的两点

    for x, y, _, _ in winners:

        if x < SIZE // 2:

            # 中左区

            xleft = max(x - window_size // 2, 0)

            xright = xleft + window_size

        else:

            # 中右区

            xright = min(x + window_size // 2, SIZE)

            xleft = xright - window_size

        if y < SIZE // 2:

            # 下半区

            ybot = max(y - window_size // 2, 0)

            ytop = ybot + window_size

        else:

            # 上半区

            ytop = min(y + window_size // 2, 0)

            ybot = ytop - window_size

        xnew = np.random.randint(xleft, xright, 1)[0]

        ynew = np.random.randint(ybot, ytop, 1)[0]

        znew = terrain[xnew, ynew]

        results.append((xnew, ynew, znew, bid))

       

    # 添加剩余随机点

    for i in range(5 - len(winners)):

        x = np.random.randint(0, SIZE, 1)[0]

        y = np.random.randint(0, SIZE, 1)[0]

        z = terrain[x, y]

        results.append((x, y, z, 2))

 

    # 找出最优两点

    winners = sorted(results, key=operator.itemgetter(2))[0:2]

    print(" best: ", winners[0])

   

best_xyz = sorted(results, key=operator.itemgetter(2))[0]

print(best_xyz)

 

xvals = [r[0] for r in results]

yvals = [r[1] for r in results]

 

plt.title("batched random search")

contour = plt.contour(terrain, linewidths=2)

plt.ylim(max(plt.ylim()), min(plt.ylim()))

plt.scatter(xvals, yvals, color="b", marker="o")

plt.scatter([best_xyz[0]], [best_xyz[1]], color='b', s=200, facecolors='none', edgecolors='b')

plt.colorbar(contour)


78a24ba0dba7b3d9c4200ac5b0f344d447c3a09b

结束时此空间中的全局最小点坐标(707,682),值为20。


显然,并不是所有的运行都是如此顺利的,也很有可能从上述任何方法发现的点只是一个局部最小值。 此外,没有理由假定网格搜索可能不优于随机搜索,因为随机地形可能在其中一个均匀布置的点下面具有其全局最小点,并且随机搜索可能错过该点。


为了检查这个假设,我对1000个随机地形批量运行上面的代码。 对于每个地形,我为3种方法中的每一种运行25个实验,并为每个方法找到最低(最优)点。我这样做了两次,以确保结果的客观性。代码如下:


 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

TERRAIN_SIZE = 1024

NUM_HILLS = 200

 

NUM_TRIALS = 1000

NUM_SEARCHES_PER_DIM = 5

NUM_WINNERS = 2

 

nbr_random_wins = 0

nbr_brand_wins = 0

for i in range(NUM_TRIALS):

    terrain = build_terrain(TERRAIN_SIZE, NUM_HILLS)

    grid_result = best_grid_search(TERRAIN_SIZE, NUM_SEARCHES_PER_DIM)

    random_result = best_random_search(TERRAIN_SIZE,

                                       NUM_SEARCHES_PER_DIM**2)

    batch_result = best_batch_random_search(TERRAIN_SIZE,

                                            NUM_SEARCHES_PER_DIM,

                                            NUM_SEARCHES_PER_DIM,

                                            NUM_WINNERS)

    print(grid_result, random_result, batch_result)

    if random_result < grid_result:

        nbr_random_wins += 1

    if batch_result < grid_result:

        nbr_brand_wins += 1

 

print("# times random search wins: {:d}".format(nbr_random_wins))

print("# times batch random search wins: {:d}".format(nbr_brand_wins))


执行结果如下:

1

2

3

4

5

6

7

8

9

Run-1

------

#-times random search wins: 619 ‘随机搜索优胜次数

#-times batch random search wins: 638 随机批量搜索优胜次数

 

Run-2

------

#-times random search wins: 640 ‘随机搜索优胜次数

#-times batch random search wins: 621随机批量搜索优胜次数


结果表明随机搜索似乎比网格搜索稍好(因为第一个数字超过500)。 此外,批量版本不一定更好,因为纯随机搜索在第二次运行有更好的结果。


以上是我实验的结果。在这个过程中,我学习了一个有趣的算法来生成地形,也为自己解除了困惑。如果你想亲自尝试,不妨阅读本文核心笔记(链接)以及批处理运行Python版本代码(链接)。

数十款阿里云产品限时折扣中,赶紧点击领劵开始云上实践吧!
作者简介:

Sujit Pal是一名程序员,在Healline Networks担任技术管理。喜好研究编程语言Java和Python,喜欢从多角度研究和解决问题。


本文由北邮@爱可可-爱生活 老师推荐,阿里云云栖社区组织翻译。


文章原标题《
Random vs Grid Search: Which is Better?》,作者:Sujit Pal ,译者:伍昆

文章为简译,更为详细的内容,请查看原文

相关文章
|
1月前
|
机器学习/深度学习 自然语言处理
《机器学习调优指南:随机搜索与网格搜索的优劣剖析》
在机器学习中,超参数调优至关重要。网格搜索和随机搜索是两种常用方法。网格搜索通过穷举所有超参数组合,确保找到全局最优解,具有全面性和可解释性强的优点,但计算成本高昂、效率低。随机搜索则从超参数空间中随机抽取组合进行评估,计算效率高且灵活性强,但在结果上存在不确定性和缺乏方向性。两者各有优劣,实际应用中可根据资源和需求选择合适的方法,甚至结合使用以提升模型性能。
156 74
|
6月前
|
机器学习/深度学习 算法
R语言超参数调优:深入探索网格搜索与随机搜索
【9月更文挑战第2天】网格搜索和随机搜索是R语言中常用的超参数调优方法。网格搜索通过系统地遍历超参数空间来寻找最优解,适用于超参数空间较小的情况;而随机搜索则通过随机采样超参数空间来寻找接近最优的解,适用于超参数空间较大或计算资源有限的情况。在实际应用中,可以根据具体情况选择适合的方法,并结合交叉验证等技术来进一步提高模型性能。
|
10月前
深度优化搜索,字典树
深度优化搜索,字典树
83 0
|
移动开发 算法
秒懂算法 | A*搜索
本篇内容包括了A*搜索算法的原理精解以及2个例题。
657 1
秒懂算法 | A*搜索
|
存储 机器学习/深度学习 算法
搜索与图论 - 搜索与图在算法中的应用【上】
搜索与图论 - 搜索与图在算法中的应用【上】
|
机器学习/深度学习 算法
搜索与图论 - 搜索与图在算法中的应用【中】
搜索与图论 - 搜索与图在算法中的应用【中】
|
存储 并行计算 算法
秒懂算法 | 搜索基础
本篇介绍了BFS和DFS的概念、性质、模板代码。
183 0
秒懂算法 | 搜索基础
【算法提高——第二讲】搜索(3)
【算法提高——第二讲】搜索(3)
【算法提高——第二讲】搜索(3)
【算法提高——第二讲】搜索(1)
【算法提高——第二讲】搜索(1)
【算法提高——第二讲】搜索(1)
|
机器学习/深度学习 算法
【第三讲】搜索与图论(2)
【第三讲】搜索与图论(2)