我刚开始了解到这个词的时候,直觉是机器学习和人类学习是类似的,机器竟然已经强大到可以像人类一样学习了,向来不自信的我就觉得这哪是我能学会的技术呢!可以说机器学习这个术语吓住了我,让我不敢尝试去进一步学习它的技术原理,直到很久以后才慢慢对它有了了解。因此我个人是不太喜欢这个词的,不知道是不是有人和我同样的原因放弃或延缓了进一步学习AI的知识。刚好最近学习《深度学习与围棋》第10章发现有一个简单的例子非常适合直观展示到底什么是机器学习中的学习,大家来体会体会。
策略学习与演示
这个例子演示如何让一个程序不断进行策略学习来赢得一个叫做“加加加”的游戏,其实就是个数字游戏,下面是它的游戏规则:
- 每一回合每人选择一个1~5的数字;
- 在100回合后,每个人将他们所选择的数字加起来;
- 总和最高的人获胜。
很显然,每个回合选择数字5就是最佳策略,书中之所以选择这么简单的游戏,就是为方便展示策略学习,观察程序如何逐步学习到这个最佳的策略的。
首先,下面的python代码用来模拟一局“加加加”游戏,传入的参数policy是选择各个数字的概率列表,返回值为100回合后胜者和负者所选择的数字次数统计。
import numpy as np
def simulate_game(policy):
"""
模拟加加加游戏,游戏介绍:
1. 两个玩家每一回合每人选择一个1~5的数字;
2. 在100回合之后,每个人将他们选择的数字加起来;
3. 总和最高的人获胜。
返回值:(胜者的选择,负者的选择)
"""
# 记录玩家选择数字1~5的次数
player_1_choices = {1: 0, 2: 0, 3: 0, 4: 0, 5: 0}
# 记录玩家选择数字的总数
player_1_total = 0
player_2_choices = {1: 0, 2: 0, 3: 0, 4: 0, 5: 0}
player_2_total = 0
# 运行100回合
for i in range(100):
# 按照policy指定的概率选择1~5中的数字
player_1_choice = np.random.choice([1, 2, 3, 4, 5], p=policy)
player_1_choices[player_1_choice] += 1
player_1_total += player_1_choice
player_2_choice = np.random.choice([1, 2, 3, 4, 5], p=policy)
player_2_choices[player_2_choice] += 1
player_2_total += player_2_choice
if player_1_total > player_2_total:
winner_choices = player_1_choices
loser_choices = player_2_choices
else:
winner_choices = player_2_choices
loser_choices = player_1_choices
return (winner_choices, loser_choices)
接下来就持续模拟游戏,初始策略是所有的数字选择概率都是相同的,为20%,每模拟一局游戏,就将胜利者选择数字的概率增加一点,而失败者选择数字的概率减少一点,这个更新选择数字概率的过程就是“学习”。下面的代码模拟了3000局游戏,并将策略的变化绘制成了曲线。
# 归一化处理选择策略
def normalize(policy):
# <0的变为0,大于1的变为1,将所有的policy的值限制在0-1范围内
policy = np.clip(policy, 0, 1)
# 归一化处理,使得所有概率的总和为1
return policy / np.sum(policy)
# 要选择的数字列表
choices = [1, 2, 3, 4, 5]
# 初始选择数字的策略,每个数字的选择概率都是20%
policy = np.array([0.2, 0.2, 0.2, 0.2, 0.2])
# 学习率,主要是为了控制策略变化的快慢
learning_rate = 0.0001
# 模拟游戏的局数
num_games = 3000
result = []
# 模拟多局游戏
for i in range(num_games):
# 模拟一局游戏(100个回合)
win_counts, lose_counts = simulate_game(policy)
# 遍历每一个要选择的数字
for j, choice in enumerate(choices):
# 计算本局胜利者选择数字的次数-失败者选择此数字的次数,表示胜者和负者的偏差
net_wins = win_counts[choice] - lose_counts[choice]
# 将选择此数字的概率根据偏差*学习率增加或减少
# 为负表明胜者倾向于少选择此数字,为正表明胜者倾向于多选择此数字
# ===注意这里就是在进行策略的学习===
policy[j] += learning_rate * net_wins
# 概率归一化处置
policy = normalize(policy)
# 记录局数、更新后的策略值
result.append((i, policy))
print(f"{i}: {policy}")
# 绘制策略的变化变化曲线
x = [i[0] for i in result]
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 设置中文字体为黑体
plt.rcParams['axes.unicode_minus'] = False # 正确显示负号
for i in range(5):
plt.plot(x, [c[1][i] for c in result], label=f"选择数字{i + 1}的概率")
plt.grid(True)
plt.legend(loc="right")
plt.title("加加加游戏策略变化曲线")
plt.show()
下图就是3000局游戏中选择数字策略的变化曲线,从图中可以看出大概2000局之后,程序就学到了最佳策略,即每次都选择数字5,也就是说程序自主学会了怎么在“加加加”游戏中获胜。深度学习要比这个例子复杂的多,但是机器学习的本质都是一样的,都是通过某些手段去调节参数以达到解决问题的目的。
图片
机器学习:一种创新的编程范式
在传统的编程实践中,我们通过精心设计的算法和逻辑来直接解决问题。这种方式要求程序员对问题有深入的理解,并且能够将解决方案明确地编码到程序中。然而,机器学习提供了一种全新的视角,它不是直接针对问题本身,而是将问题转化为数学模型,然后利用数据来训练模型,使其能够自动学习和找到解决问题的方法。
这种范式转变带来了几个关键的思维创新:
- 抽象和泛化:机器学习将具体问题抽象为数学模型,这使得模型能够在不同情境下泛化,解决更广泛的问题。
- 数据驱动的决策:在机器学习中,决策过程是基于数据的,模型通过分析大量数据来学习如何做出预测或决策。
- 自动化的特征工程:传统编程中,特征提取和工程通常需要领域专家的深入参与。机器学习,尤其是深度学习,能够自动从原始数据中学习特征,减少了对专家知识的依赖。
- 迭代和自适应:机器学习模型可以通过迭代训练过程不断优化,它们能够适应新的数据和变化的环境。
- 跨领域的应用:机器学习的方法论可以应用于各种领域,从图像识别到自然语言处理,从医疗诊断到股票市场分析,其应用范围广泛。
将机器学习视为一种编程范式,有助于我们更好地理解其核心价值和潜力。它不仅仅是一系列算法和技术的集合,更是一种全新的思考和解决问题的方式。这种思维方式的创新为解决复杂问题提供了新的可能性,并且正在不断推动科技和社会的进步。