一、基本概率论

        注意!概率论只是深度学习的预备知识,我这里只对代码部分做出解释,想要进一步了解概率论,可以看书或者找视频。现在不看也行,等后面遇到了再补。

        书上的掷骰子的例子,我们这里也用这个例子。只不过我对代码进行了修改,不用d2l包,而是直接使用matplotlib来绘制散点图。

        首先设置环境变量:os.environ['KMP_DUPLICATE_LIB_OK'] = 'True',这是为了解决 OpenMP 库冲突引。
        当PyTorch和另一个库(Matplotlib)都尝试初始化OpenMP时,可能会发生冲突。这段代码是为了告诉 OpenMP:"允许多个库初始化同一个 OpenMP 库,不要报错"

        plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei']
        plt.rcParams['axes.unicode_minus'] = False
        这段代码是用于配置 matplotlib 的字体设置,主要解决中文显示和负号显示的问题。

        fair_probs = torch.ones([6]) / 6  #创建公平概率的骰子,每个概率都是1/6
        print("公平骰子概率:", fair_probs)

        现在我们已经创建了一个骰子,现在我们开始摇骰子。
        Multinomial(total_count, probs)# total_count表示实验的次数,也就是掷骰子的次数,probs表示掷骰子的概率。
        sample()#表示抽样,也就是做了多少次抽样,没有参数默认1次。
        counts = multinomial.Multinomial(10, fair_probs).sample((500,))# 表示进行500组实验,每组10次掷骰,每个面的概率等于我们之前设置的1/6

        # 计算累积和(沿着实验组数维度)
        cum_counts = counts.cumsum(dim=0)
        # 第n行 = 前n组实验的累计结果
        # 例如: cum_counts[0] = 第1组结果
        #          cum_counts[1] = 第1+2组结果
        #          cum_counts[49] = 前50组结果

        # 计算累计的相对频率
        estimates = cum_counts / cum_counts.sum(dim=1, keepdims=True)
        # 每个概率 = 累计出现次数 / 总实验次数

以下是所有代码:
注意!我把书上的单次投掷和1000次也给写了上去,为了方便对比结果。

import os
os.environ['KMP_DUPLICATE_LIB_OK'] = 'True'  # 必须放在最开头

import torch
from torch.distributions import multinomial
import matplotlib.pyplot as plt
import numpy as np

# 设置中文字体(可选)
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False

# 1. 创建公平骰子概率
fair_probs = torch.ones([6]) / 6
print("公平骰子概率:", fair_probs)

# 2. 模拟掷骰子
print("\n--- 单次掷骰子 ---")
one_roll = multinomial.Multinomial(1, fair_probs).sample()
print("结果:", one_roll)
print("掷出的是第", torch.argmax(one_roll).item() + 1, "面")

print("\n--- 10次掷骰子 ---")
ten_rolls = multinomial.Multinomial(10, fair_probs).sample()
print("结果:", ten_rolls)
print("频率:", ten_rolls / 10)

print("\n--- 1000次掷骰子 ---")
thousand_rolls = multinomial.Multinomial(1000, fair_probs).sample()
print("结果:", thousand_rolls)
print("频率:", thousand_rolls / 1000)

# 3. 大数定律演示
print("\n--- 大数定律演示 ---")
# 进行500组实验,每组10次掷骰
counts = multinomial.Multinomial(10, fair_probs).sample((500,))
print("实验数据形状:", counts.shape)  # (500, 6)

# 计算累积结果
cum_counts = counts.cumsum(dim=0)  # 沿实验组数维度累积
print("累积数据形状:", cum_counts.shape)  # (500, 6)

# 计算累计概率估计
estimates = cum_counts / cum_counts.sum(dim=1, keepdims=True)
print("概率估计形状:", estimates.shape)  # (500, 6)

# 4. 绘制图表
plt.figure(figsize=(10, 6))#创建宽10寸,高6寸的窗口

# 绘制每个面的概率曲线
for i in range(6):
    plt.plot(estimates[:, i].numpy(),#获取所有实验组中第i+1个面的概率估计
             label=f"P(骰子={i+1})",
             linewidth=2)

# 添加真实概率参考线
plt.axhline(y=1/6, color='black', linestyle='dashed',#真实概率的线在y = 1/6的位置
            linewidth=1, label='真实概率 (1/6)')

plt.xlabel('实验组数 (每组10次掷骰)')
plt.ylabel('估计概率')
plt.title('大数定律演示: 随着实验次数增加,频率收敛到概率')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()

# 5. 验证收敛性
print("\n--- 收敛性验证 ---")
print("前10组实验的平均概率:", estimates[9].numpy().round(3))
print("前100组实验的平均概率:", estimates[99].numpy().round(3))
print("所有500组实验的平均概率:", estimates[-1].numpy().round(3))
#所有500组实验后的最终概率(-1表示最后一个) round(3)是四舍五入保留三位小数
print("真实概率:", [round(1/6, 3)] * 6)

运行结果:

公平骰子概率: tensor([0.1667, 0.1667, 0.1667, 0.1667, 0.1667, 0.1667])

--- 单次掷骰子 ---
结果: tensor([0., 0., 0., 0., 0., 1.])
掷出的是第 6 面

--- 10次掷骰子 ---
结果: tensor([0., 3., 3., 1., 2., 1.])
频率: tensor([0.0000, 0.3000, 0.3000, 0.1000, 0.2000, 0.1000])

--- 1000次掷骰子 ---
结果: tensor([159., 161., 160., 185., 157., 178.])
频率: tensor([0.1590, 0.1610, 0.1600, 0.1850, 0.1570, 0.1780])

--- 大数定律演示 ---
实验数据形状: torch.Size([500, 6])
累积数据形状: torch.Size([500, 6])
概率估计形状: torch.Size([500, 6])

--- 收敛性验证 ---
前10组实验的平均概率: [0.18 0.23 0.14 0.16 0.12 0.17]
前100组实验的平均概率: [0.183 0.184 0.156 0.155 0.168 0.154]
所有500组实验的平均概率: [0.168 0.171 0.163 0.172 0.159 0.167]
真实概率: [0.167, 0.167, 0.167, 0.167, 0.167, 0.167]

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐