使用 NumPy 中的真实数据确定摩尔定律#

MOS 晶体管数量每两年在微处理器中的散点图,作为摩尔定律的演示。

给定芯片报告的晶体管数量在y轴上以对数刻度绘制,引入日期在x轴上以线性刻度绘制。蓝色数据点来自晶体管数量表。红线是普通最小二乘预测,橙线是摩尔定律。

你将做什么#

在1965年,工程师戈登·摩尔预测在接下来的十年里,芯片上的晶体管数量将每两年翻一番[1, 2]。你将比较摩尔的预测与他在预测后53年内的实际晶体管数量。你将确定最佳拟合常数,以描述半导体上晶体管数量的指数增长与摩尔定律的比较。

你将学到的技能#

  • *.csv文件加载数据

  • 使用普通最小二乘法进行线性回归并预测指数增长

  • 你将比较模型之间的指数增长常数

  • 在文件中分享你的分析:

    • 作为 NumPy 压缩文件 *.npz

    • 作为 *.csv 文件

  • 评估半导体制造商在过去五十年中取得的惊人进展

你需要什么#

1. 这些包:

通过以下命令导入

import matplotlib.pyplot as plt
import numpy as np

2. 由于这是一个指数增长定律,你需要一些关于使用 自然对数指数函数 进行数学运算的背景知识。

你将使用这些 NumPy 和 Matplotlib 函数:

  • np.loadtxt: 此函数将文本加载到NumPy数组中

  • np.log: 此函数计算NumPy数组中所有元素的自然对数

  • np.exp: 这个函数计算一个NumPy数组中所有元素的指数

  • lambda: 这是一个创建函数模型的最小函数定义

  • plt.semilogy: 此函数将在一个具有线性x轴和对数\(\log_{10}\) y轴的图上绘制x-y数据 plt.plot: 此函数将在线性轴上绘制x-y数据

  • 切片数组:查看加载到工作区中的数据部分,切片数组例如 x[:10] 表示数组 x 中的前10个值

  • 布尔数组索引:要查看与给定条件匹配的数据部分,使用布尔运算来索引数组

  • np.block: 将数组组合成二维数组

  • np.newaxis: 将一维向量转换为行向量或列向量

  • np.saveznp.savetxt: 这两个函数将分别以压缩数组格式和文本保存您的数组。


将摩尔定律构建为指数函数#

你的经验模型假设每个半导体中的晶体管数量遵循指数增长,

\(\log(\text{晶体管数量})= f(\text{年份}) = A\cdot \text{年份}+B,\)

其中 \(A\)\(B\) 是拟合常数。您使用半导体制造商的数据来找到拟合常数。

您通过指定增加的晶体管速率(2)并为某一年提供初始晶体管数量来确定摩尔定律的这些常数。

你以指数形式陈述摩尔定律如下,

\(\text{transistor_count}= e^{A_M\cdot \text{year} +B_M}.\)

其中 \(A_M\)\(B_M\) 是常数,每两年将晶体管数量翻倍,并在1971年从2250个晶体管开始。

  1. \(\dfrac{\text{transistor_count}(\text{year} +2)}{\text{transistor_count}(\text{year})} = 2 = \dfrac{e^{B_M}e^{A_M \text{year} + 2A_M}}{e^{B_M}e^{A_M \text{year}}} = e^{2A_M} \rightarrow A_M = \frac{\log(2)}{2}\)

  2. \(\log(2250) = \frac{\log(2)}{2}\cdot 1971 + B_M \rightarrow B_M = \log(2250)-\frac{\log(2)}{2}\cdot 1971\)

因此,摩尔定律作为指数函数表示为

\(\log(\text{晶体管数量})= A_M\cdot \text{年份}+B_M,\)

哪里

\(A_M=0.3466\)

\(B_M=-675.4\)

由于该函数表示摩尔定律,请使用 lambda 将其定义为 Python 函数

A_M = np.log(2) / 2
B_M = np.log(2250) - A_M * 1971
Moores_law = lambda year: np.exp(B_M) * np.exp(A_M * year)

在1971年,Intel 4004芯片上有2250个晶体管。使用 Moores_law 来检查戈登·摩尔预计在1973年会有多少个半导体。

ML_1971 = Moores_law(1971)
ML_1973 = Moores_law(1973)
print("In 1973, G. Moore expects {:.0f} transistors on Intels chips".format(ML_1973))
print("This is x{:.2f} more transistors than 1971".format(ML_1973 / ML_1971))
In 1973, G. Moore expects 4500 transistors on Intels chips
This is x2.00 more transistors than 1971

加载历史制造数据到您的工作区#

现在,基于每个芯片的历史半导体数据进行预测。每年的晶体管数量[4]transistor_data.csv文件中。在将*.csv文件加载到NumPy数组之前,最好先检查文件的结构。然后,找到感兴趣的列并将它们保存到一个变量中。将文件中的两列保存到数组data中。

在这里,打印出 transistor_data.csv 的前 10 行。列是

处理器

MOS 晶体管计数

介绍日期

设计师

MOSprocess

区域

Intel 4004 (4位 16引脚)

2250

1971

英特尔

10,000 纳米

12 mm²

! head transistor_data.csv
Processor,MOS transistor count,Date of Introduction,Designer,MOSprocess,Area
Intel 4004 (4-bit  16-pin),2250,1971,Intel,"10,000 nm",12 mm²
Intel 8008 (8-bit  18-pin),3500,1972,Intel,"10,000 nm",14 mm²
NEC μCOM-4 (4-bit  42-pin),2500,1973,NEC,"7,500 nm",?
Intel 4040 (4-bit  16-pin),3000,1974,Intel,"10,000 nm",12 mm²
Motorola 6800 (8-bit  40-pin),4100,1974,Motorola,"6,000 nm",16 mm²
Intel 8080 (8-bit  40-pin),6000,1974,Intel,"6,000 nm",20 mm²
TMS 1000 (4-bit  28-pin),8000,1974,Texas Instruments,"8,000 nm",11 mm²
MOS Technology 6502 (8-bit  40-pin),4528,1975,MOS Technology,"8,000 nm",21 mm²
Intersil IM6100 (12-bit  40-pin; clone of PDP-8),4000,1975,Intersil,,

你不需要指定 处理器设计者MOS工艺面积 的列。这剩下第二列和第三列,分别是 MOS 晶体管数量引入日期

接下来,您使用 np.loadtxt 将这两列加载到一个 NumPy 数组中。下面的额外选项将使数据格式化为所需的形式:

  • delimiter = ',': 指定分隔符为逗号 ‘,’(这是默认行为)

  • usecols = [1,2]: 从csv中导入第二列和第三列

  • skiprows = 1: 不要使用第一行,因为它是一个标题行

data = np.loadtxt("transistor_data.csv", delimiter=",", usecols=[1, 2], skiprows=1)

你将整个半导体历史加载到一个名为 data 的 NumPy 数组中。第一列是 MOS 晶体管数量 ,第二列是 引入日期 ,以四位数年份表示。

接下来,通过将两列分配给变量 yeartransistor_count 来使数据更易于阅读和管理。通过使用 [:10]yeartransistor_count 数组进行切片,打印出前10个值。打印这些值以检查您是否已将数据保存到正确的变量中。

year = data[:, 1]  # grab the second column and assign
transistor_count = data[:, 0]  # grab the first column and assign

print("year:\t\t", year[:10])
print("trans. cnt:\t", transistor_count[:10])
year:		 [1971. 1972. 1973. 1974. 1974. 1974. 1974. 1975. 1975. 1975.]
trans. cnt:	 [2250. 3500. 2500. 3000. 4100. 6000. 8000. 4528. 4000. 5000.]

你正在创建一个根据给定年份预测晶体管数量的函数。你有一个 自变量year,和一个 因变量transistor_count。将因变量转换为对数尺度。

\(y_i = \log(\) transistor_count[i] \(),\)

从而得到一个线性方程,

\(y_i = A\cdot \text{年份} +B\).

yi = np.log(transistor_count)

计算晶体管的历史增长曲线#

你的模型假设 yiyear 的函数。现在,找到最佳拟合模型,使 \(y_i\)\(A\cdot \text{year} + B\) 之间的差异最小化。

\(\min \sum|y_i - (A\cdot \text{year}_i + B)|^2.\)

这个 平方和误差 可以简洁地表示为数组,如下所示

\(\sum|\mathbf{y}-\mathbf{Z} [A,~B]^T|^2,\)

其中\(\mathbf{y}\)是1D数组中晶体管数量的对数观测值,\(\mathbf{Z}=[\text{year}_i^1,~\text{year}_i^0]\)\(\text{year}_i\)的多项式项,分别位于第一列和第二列。通过在\(\mathbf{Z}-\)矩阵中创建这组回归变量,您设置了一个普通最小二乘统计模型。

Z 是一个具有两个参数的线性模型,即一个次数为 1 的多项式。因此,我们可以用 numpy.polynomial.Polynomial 来表示该模型,并使用拟合功能来确定模型参数:

model = np.polynomial.Polynomial.fit(year, yi, deg=1)

默认情况下,Polynomial.fit 在由自变量(在此例中为 year)确定的域中执行拟合。未缩放和未移位模型的系数可以通过 convert 方法恢复:

model = model.convert()
model
\[x \mapsto \text{-666.32640635} + \text{0.34163208}\,x\]

个体参数 \(A\)\(B\) 是我们线性模型的系数:

B, A = model

制造商是否每两年将晶体管数量翻倍?你已经有了最终的公式,

\(\dfrac{\text{transistor_count}(\text{year} +2)}{\text{transistor_count}(\text{year})} = xFactor = \dfrac{e^{B}e^{A( \text{year} + 2)}}{e^{B}e^{A \text{year}}} = e^{2A}\)

其中,晶体管数量的增加是 \(xFactor\),年数是 2,而 \(A\) 是半对数函数上的最佳拟合斜率。

print(f"Rate of semiconductors added on a chip every 2 years: {np.exp(2 * A):.2f}")
Rate of semiconductors added on a chip every 2 years: 1.98

基于你的最小二乘回归模型,每两年芯片上的半导体数量增加了 \(1.98\) 倍。你有一个模型可以预测每年的半导体数量。现在将你的模型与实际制造报告进行比较。绘制线性回归结果和所有晶体管计数。

在这里,使用 plt.semilogy 在对数尺度上绘制晶体管数量,并在线性尺度上绘制年份。你已经定义了三个数组以得到最终模型

\(y_i = \log(\text{晶体管数量}),\)

\(y_i = A \cdot \text{年份} + B,\)

\(\log(\text{晶体管数量}) = A\cdot \text{年份} + B,\)

你的变量 transistor_countyearyi 都有相同的维度,(179,)。NumPy 数组需要相同的维度来绘制图表。预测的晶体管数量现在是

\(\text{transistor_count}_{\text{predicted}} = e^Be^{A\cdot \text{year}}\).

在下一个图表中,使用 fivethirtyeight 样式表。该样式表复制了 https://fivethirtyeight.com 的元素。使用 plt.style.use 更改 matplotlib 样式。

transistor_count_predicted = np.exp(B) * np.exp(A * year)
transistor_Moores_law = Moores_law(year)
plt.style.use("fivethirtyeight")
plt.semilogy(year, transistor_count, "s", label="MOS transistor count")
plt.semilogy(year, transistor_count_predicted, label="linear regression")


plt.plot(year, transistor_Moores_law, label="Moore's Law")
plt.title(
    "MOS transistor count per microprocessor\n"
    + "every two years \n"
    + "Transistor count was x{:.2f} higher".format(np.exp(A * 2))
)
plt.xlabel("year introduced")
plt.legend(loc="center left", bbox_to_anchor=(1, 0.5))
plt.ylabel("# of transistors\nper microprocessor")
Text(0, 0.5, '# of transistors\nper microprocessor')
../_images/cf6ee1b020c3c017700c0c826d6aa21aa0e4601affcdbcd77a3cdb52c11781f0.png

每两年每个微处理器的MOS晶体管数量的散点图,红色线表示普通最小二乘法预测,橙色线表示摩尔定律。

线性回归捕捉到了每年每个半导体晶体管数量的增加。2015年,半导体制造商声称他们再也无法跟上摩尔定律了。你的分析显示,自1971年以来,晶体管数量的平均增加是每2年x1.98,但戈登·摩尔预测的是每2年x2。这是一个惊人的预测。

考虑2017年。将数据与你的线性回归模型和戈登·摩尔的预测进行比较。首先,获取2017年的晶体管数量。你可以使用布尔比较器来完成这项工作。

year == 2017.

然后,使用上面定义的 Moores_law 对2017年进行预测,并将你最佳拟合常数代入你的函数中。

\(\text{transistor_count} = e^{B}e^{A\cdot \text{year}}\).

比较这些测量值的一个好方法是,将你的预测和摩尔的预测与平均晶体管数量进行比较,并查看该年份报告值的范围。使用 plt.plot 选项,alpha=0.2,来增加数据的透明度。点越不透明,表示在该测量值上的报告值越多。绿色的 \(+\) 是2017年报告的平均晶体管数量。绘制你对 \(\pm\frac{1}{2}~years\) 的预测。

transistor_count2017 = transistor_count[year == 2017]
print(
    transistor_count2017.max(), transistor_count2017.min(), transistor_count2017.mean()
)
y = np.linspace(2016.5, 2017.5)
your_model2017 = np.exp(B) * np.exp(A * y)
Moore_Model2017 = Moores_law(y)

plt.plot(
    2017 * np.ones(np.sum(year == 2017)),
    transistor_count2017,
    "ro",
    label="2017",
    alpha=0.2,
)
plt.plot(2017, transistor_count2017.mean(), "g+", markersize=20, mew=6)

plt.plot(y, your_model2017, label="Your prediction")
plt.plot(y, Moore_Model2017, label="Moores law")
plt.ylabel("# of transistors\nper microprocessor")
plt.legend()
19200000000.0 250000000.0 7050000000.0
<matplotlib.legend.Legend at 0x130f5e330>
../_images/a870c2451836a0cd039125091cb570356499d681245b92b6455e1e517513b423.png

结果是你的模型接近平均值,但戈登·摩尔的预测更接近2017年每个微处理器生产的最大晶体管数量。尽管半导体制造商认为增长会放缓,一次是在1975年,现在再次接近2025年,制造商仍然每2年生产一次几乎使晶体管数量翻倍的半导体。

线性回归模型在预测平均值方面比预测极端值要好得多,因为它满足最小化 \(\sum |y_i - A\cdot \text{year}[i]+B|^2\) 的条件。

将你的结果作为压缩数组和csv文件共享#

最后一步是分享你的发现。你创建了新的数组,这些数组代表了一个线性回归模型和戈登·摩尔的预测。你通过使用 np.loadtxt 将一个 csv 文件导入到一个 NumPy 数组中开始了这个过程,为了保存你的模型,请使用两种方法

  1. np.savez: 保存 NumPy 数组以供其他 Python 会话使用

  2. np.savetxt: 保存一个包含原始数据和你预测数据的csv文件

将数组压缩成文件#

使用 np.savez,你可以保存成千上万的数组并为它们命名。函数 np.load 会将数组作为字典加载回工作区。你将保存五个数组,以便下一个用户可以获得年份、晶体管数量、预测的晶体管数量、戈登·摩尔的预测数量和拟合常数。添加一个其他用户可以用来理解模型的变量,notes

notes = "the arrays in this file are the result of a linear regression model\n"
notes += "the arrays include\nyear: year of manufacture\n"
notes += "transistor_count: number of transistors reported by manufacturers in a given year\n"
notes += "transistor_count_predicted: linear regression model = exp({:.2f})*exp({:.2f}*year)\n".format(
    B, A
)
notes += "transistor_Moores_law: Moores law =exp({:.2f})*exp({:.2f}*year)\n".format(
    B_M, A_M
)
notes += "regression_csts: linear regression constants A and B for log(transistor_count)=A*year+B"
print(notes)
the arrays in this file are the result of a linear regression model
the arrays include
year: year of manufacture
transistor_count: number of transistors reported by manufacturers in a given year
transistor_count_predicted: linear regression model = exp(-666.33)*exp(0.34*year)
transistor_Moores_law: Moores law =exp(-675.38)*exp(0.35*year)
regression_csts: linear regression constants A and B for log(transistor_count)=A*year+B
np.savez(
    "mooreslaw_regression.npz",
    notes=notes,
    year=year,
    transistor_count=transistor_count,
    transistor_count_predicted=transistor_count_predicted,
    transistor_Moores_law=transistor_Moores_law,
    regression_csts=(A, B),
)
results = np.load("mooreslaw_regression.npz")
print(results["regression_csts"][1])
-666.3264063536225
! ls
_static
air-quality-data.csv
mooreslaw-tutorial.md
mooreslaw_regression.csv
mooreslaw_regression.npz
pairing.md
save-load-arrays.md
text_preprocessing.py
transistor_data.csv
tutorial-air-quality-analysis.md
tutorial-deep-learning-on-mnist.md
tutorial-deep-reinforcement-learning-with-pong-from-pixels.md
tutorial-ma.md
tutorial-nlp-from-scratch
tutorial-nlp-from-scratch.md
tutorial-plotting-fractals
tutorial-plotting-fractals.md
tutorial-static_equilibrium.md
tutorial-style-guide.md
tutorial-svd.md
tutorial-x-ray-image-processing
tutorial-x-ray-image-processing.md
who_covid_19_sit_rep_time_series.csv
x_y-squared.csv
x_y-squared.npz

np.savez 的好处是你可以保存数百个具有不同形状和类型的数组。这里,你保存了4个形状为 (179,) 的双精度浮点数数组,一个文本数组,和一个形状为 (2,) 的双精度浮点数数组。这是保存用于其他分析的NumPy数组的推荐方法。

创建你自己的逗号分隔值文件#

如果你想共享数据并在表格中查看结果,那么你必须创建一个文本文件。使用 np.savetxt 保存数据。这个函数比 np.savez 更有限。分隔文件,如 csv,需要二维数组。

通过创建一个新的二维数组来准备导出数据,该数组的列包含感兴趣的数据。

使用 header 选项来描述数据和文件的列。定义另一个包含文件信息的变量为 head

head = "the columns in this file are the result of a linear regression model\n"
head += "the columns include\nyear: year of manufacture\n"
head += "transistor_count: number of transistors reported by manufacturers in a given year\n"
head += "transistor_count_predicted: linear regression model = exp({:.2f})*exp({:.2f}*year)\n".format(
    B, A
)
head += "transistor_Moores_law: Moores law =exp({:.2f})*exp({:.2f}*year)\n".format(
    B_M, A_M
)
head += "year:, transistor_count:, transistor_count_predicted:, transistor_Moores_law:"
print(head)
the columns in this file are the result of a linear regression model
the columns include
year: year of manufacture
transistor_count: number of transistors reported by manufacturers in a given year
transistor_count_predicted: linear regression model = exp(-666.33)*exp(0.34*year)
transistor_Moores_law: Moores law =exp(-675.38)*exp(0.35*year)
year:, transistor_count:, transistor_count_predicted:, transistor_Moores_law:

构建一个单一的2D数组以导出到csv。表格数据本质上是二维的。你需要组织你的数据以适应这种2D结构。分别使用 year, transistor_count, transistor_count_predicted, 和 transistor_Moores_law 作为第一到第四列。将计算的常量放在头部,因为它们不符合 (179,) 的形状。使用 np.block 函数将数组附加在一起以创建一个新的、更大的数组。使用 np.newaxis 将1D向量排列为列,例如。

>>> year.shape
(179,)
>>> year[:,np.newaxis].shape
(179,1)
output = np.block(
    [
        year[:, np.newaxis],
        transistor_count[:, np.newaxis],
        transistor_count_predicted[:, np.newaxis],
        transistor_Moores_law[:, np.newaxis],
    ]
)

使用 np.savetxt 创建 mooreslaw_regression.csv,使用三个选项来创建所需的文件格式:

  • X = output : 使用 output 块将数据写入文件

  • delimiter = ',' : 使用逗号分隔文件中的列

  • header = head : 使用上面定义的头部 head

np.savetxt("mooreslaw_regression.csv", X=output, delimiter=",", header=head)
! head mooreslaw_regression.csv
# the columns in this file are the result of a linear regression model
# the columns include
# year: year of manufacture
# transistor_count: number of transistors reported by manufacturers in a given year
# transistor_count_predicted: linear regression model = exp(-666.33)*exp(0.34*year)
# transistor_Moores_law: Moores law =exp(-675.38)*exp(0.35*year)
# year:, transistor_count:, transistor_count_predicted:, transistor_Moores_law:
1.971000000000000000e+03,2.250000000000000000e+03,1.130514785642463039e+03,2.249999999999916326e+03
1.972000000000000000e+03,3.500000000000000000e+03,1.590908400344390429e+03,3.181980515339620069e+03
1.973000000000000000e+03,2.500000000000000000e+03,2.238793840142484441e+03,4.500000000000097316e+03

总结#

总之,您已经比较了半导体制造商的历史数据与摩尔定律,并创建了一个线性回归模型来找到每两年添加到每个微处理器中的平均晶体管数量。戈登·摩尔预测从1965年到1975年,晶体管数量将每两年翻一番,但从1971年到2019年,平均增长一直保持在每两年 \(\times 1.98 \pm 0.01\) 的增长。2015年,摩尔修订了他的预测,称摩尔定律应持续到2025年。[3]。您可以将这些结果分享为一个压缩的NumPy数组文件,mooreslaw_regression.npz,或另一个csv文件,mooreslaw_regression.csv。半导体制造的惊人进步已经启用了新的行业和计算能力。这一分析应让您略微了解过去半个世纪这一增长是多么不可思议。

参考文献#

  1. “摩尔定律.” 维基百科文章. 访问于2020年10月1日.

  2. Moore, Gordon E. (1965-04-19). “在集成电路上塞入更多组件”. intel.com. Electronics Magazine. 检索于2020年4月1日.

  3. Courtland, Rachel. “Gordon Moore: 名字意味着进步的人。” IEEE Spectrum. 2015年3月30日。.

  4. “晶体管数量。” 维基百科文章。访问于2020年10月1日。