新版 Macbook 已经问世了一段时间,如果将 M1 芯片用于数据科学,功能会如何呢?本文作者将 M1 Macbook Pro 与基于 Intel 的 2019 Macbook Pro 在 5 种常用基准上进行了尝试,结果发现 M1 芯片的功能确实是令人震惊的。
首先,它的运转速率比 2019 MBP 是快几倍的,并且运转过程中完全保持安静。我施行了多 CPU 的困难恣意,散热扇甚至都没有发动过。当然,还有电池寿命也令人难以置信,重度使用多达 14 小时也不会出现问题。
尝试的基准共有 5 种:
CPU 和 GPU 基准;
功能尝试——纯 Python;
功能尝试——Numpy;
功能尝试——Pandas;
功能尝试——Scikit-Learn。
本文的所有比较都是在两个 Macbook Pro 之间进行的:
2019 Macbook Pro(i5-8257U @ 1.40 GHz / 8 GB LPDDR3 / Iris Plus 645 1536 MB)——Intel MBP 13-inch 2019
2020 M1 Macbook Pro(M1 @ 3.19 GHz / 8GB)——M1 MBP 13-inch 2020
并非所有库都与新 M1 芯片兼容。目前配置 Numpy 和 TensorFlow 没问题,但是 Pandas 和 Scikit-Learn 还不能在本地运转 – 至少我没有找到可用的版本。
唯一可行的解决方案是通过 Anaconda 安装这两个库,但需要通过 Rosseta 2 仿真器运转,因此它比本机要慢一些。
你将看到的尝试在任何形式上都不是「科学的」。他们仅仅比较了上述机器之间在一组不同的编程和数据科学恣意中的运转时。
CPU 和 GPU 基准
我们首先从基本的 CPU 和 GPU 基准开始。使用 Geekbench 5 进行尝试的结果下列表:
图 1:Geekbench 比较(CPU 和 GPU)。
M1 芯片在 2019 Mac 中超越了 Intel 芯片。该基准尝试仅衡量整体机器功能,与本文要进行的数据科学基准尝试并不是百分百相关。
功能尝试——纯 Python
下列是在该基准中施行的恣意列表:
创建一个包含 100 至 999 之间的 100000000 随机整数的列表 l;
对列表 l 中的每个项目求平方;
取 l 中每一项的平方根;
将相应的平方和平方根相乘;
相应的平方和平方根相除;
对相应的平方和平方根进行整除运算。
该尝试仅使用内置 Python 库,不含 Numpy。下列是尝试的代码段
import random time_start = datetime.now() l = [random.randrange(100, 999) for i in range(100000000)] squared = [x**2 for x in l] sqrt = [x**0.5 for x in l] mul = [x * y for x, y in zip(squared, sqrt)] div = [x / y for x, y in zip(squared, sqrt)] int_div = [x // y for x, y in zip(squared, sqrt)] time_end = datetime.now() print(f'TOTAL TIME = {(time_end - time_start).seconds} seconds')
结果下列:
图 2:Python 速率尝试,越低为越好。
通过 Anaconda(和 Rosseta 2)在 M1 Mac 上运转的 Python 减少了 196 秒的运转时。最好是在本地运转 Python,因为这样就能将运转时进一步减少 43 秒。
功能尝试——Numpy
下列是在该基准中施行的恣意列表:
矩阵乘法
向量乘法
奇异值分解
Cholesky 分解
特征分解
脚本下列
# SOURCE: https://gist.github.com/markus-beuckelmann/8bc25531b11158431a5b09a45abd6276 import numpy as np from time import time from datetime import datetime start_time = datetime.now() # Let's take the randomness out of random numbers (for reproducibility) np.random.seed(0) size = 4096 A, B = np.random.random((size, size)), np.random.random((size, size)) C, D = np.random.random((size * 128,)), np.random.random((size * 128,)) E = np.random.random((int(size / 2), int(size / 4))) F = np.random.random((int(size / 2), int(size / 2))) F = np.dot(F, F.T) G = np.random.random((int(size / 2), int(size / 2))) # Matrix multiplication N = 20 t = time() for i in range(N): np.dot(A, B) delta = time() - t print('Dotted two %dx%d matrices in %0.2f s.' % (size, size, delta / N)) del A, B # Vector multiplication N = 5000 t = time() for i in range(N): np.dot(C, D) delta = time() - t print('Dotted two vectors of length %d in %0.2f ms.' % (size * 128, 1e3 * delta / N)) del C, D # Singular Value Decomposition (SVD) N = 3 t = time() for i in range(N): np.linalg.svd(E, full_matrices = False) delta = time() - t print("SVD of a %dx%d matrix in %0.2f s." % (size / 2, size / 4, delta / N)) del E # Cholesky Decomposition N = 3 t = time() for i in range(N): np.linalg.cholesky(F) delta = time() - t print("Cholesky decomposition of a %dx%d matrix in %0.2f s." % (size / 2, size / 2, delta / N)) # Eigendecomposition t = time() for i in range(N): np.linalg.eig(G) delta = time() - t print("Eigendecomposition of a %dx%d matrix in %0.2f s." % (size / 2, size / 2, delta / N)) print('') end_time = datetime.now() print(f'TOTAL TIME = {(end_time - start_time).seconds} seconds')
尝试结果下列:
图 3:Numpy 速率尝试,越低越好。
在 Numpy 上得到的结果有点奇怪。Numpy 似乎在 2019 Intel Mac 上运转得更快,作者猜想原因可能在于进行了一些优化。
功能尝试——Pandas
Pandas 基准非常类似于 Python。二者施行了相同的操作,但结果被合并为单个数据 frame。
下列是恣意列表:
创建一个空的数据 frame;
为它分配含 100 到 999 之间 100,000,000 个随机整数的 column(X);
将 X 中的每一项平方;
取 X 中每一项的平方根;
对应的平方和平方根相乘;
对应的平方和平方根相除;
对对应的平方和平方根施行整数除法。
下列是尝试代码段:
import numpy as np import pandas as pd from datetime import datetime time_start = datetime.now() df = pd.DataFrame() df['X'] = np.random.randint(low=100, high=999, size=100000000) df['X_squared'] = df['X'].apply(lambda x: x**2) df['X_sqrt'] = df['X'].apply(lambda x: x**0.5) df['Mul'] = df['X_squared'] * df['X_sqrt'] df['Div'] = df['X_squared'] / df['X_sqrt'] df['Int_div'] = df['X_squared'] // df['X_sqrt'] time_end = datetime.now() print(f'Total time = {(time_end - time_start).seconds} seconds')
结果下列:
图 4:Pandas 速率尝试——越低越好
需要注意的是这里没有安装本机 Pandas,但 M1 芯片上的 Pandas 以快了 2 倍的速率完成了该基准尝试。
功能尝试——Scikit-Learn
与 Pandas 一样,这里也没有在本机上安装 Scikit-Learn,只有通过 Rosseta 2 仿真器运转的 Intel MBP 和 M1 MBP 的比较结果。
下列是在该基准尝试中施行的恣意列表:
从网络上获取数据集;
施行训练 / 尝试 split;
声明一个决策树模型并找到最佳超参数(2400 个组合 + 5 倍交叉验证);
使用最佳参数拟合模型。
这是一个大致的标准模型训练程序,但不包含尝试多种算法,数据准备和特征工程。下列是尝试的代码段:
from sklearn.tree import DecisionTreeClassifier from sklearn.model_selection import train_test_split, GridSearchCV from sklearn.metrics import accuracy_score, confusion_matrix time_start = datetime.now() # Dataset iris = pd.read_csv('https://gist.githubusercontent.com/curran/a08a1080b88344b0c8a7/raw/0e7a9b0a5d22642a06d3d5b9bcbad9890c8ee534/iris.csv') time_load = datetime.now() print(f'Dataset loaded, runtime = {(time_load - time_start).seconds} seconds') # Train/Test split X = iris.drop('species', axis=1) y = iris['species'] X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25) time_split = datetime.now() print(f'Train/test split, runtime = {(time_split - time_start).seconds} seconds') # Hyperparameter tuning model = DecisionTreeClassifier() params = {' criterion': ['gini', 'entropy'], 'splitter': ['best', 'random'], 'max_depth': [1, 5, 10, 50, 100, 250, 500, 1000], 'min_samples_split': [2, 5, 10, 15, 20], 'min_samples_leaf': [1, 2, 3, 4, 5], 'max_features': ['auto', 'sqrt', 'log2'] } clf = GridSearchCV( estimator=model, param_grid=params, cv=5 ) clf.fit(X_train, y_train) time_optim = datetime.now() print(f'Hyperparameter optimization, runtime = {(time_optim - time_start).seconds} seconds') best_model = DecisionTreeClassifier(**clf.best_params_) best_model.fit(X_train, y_train) time_end = datetime.now() print() print(f'TOTAL RUNTIME = {(time_end - time_start).seconds} seconds')
结果下列:
图 5:Scikit-Learn 速率尝试——越低越好。
结果传达了和使用 Pandas 尝试时相同的信息——2019 Intel i5 处理器用两倍时长才完成了相同的恣意。
新的 M1 芯片绝对是物有所值的,但最好的版本还在后面,毕竟这只是第一代。
原文链接:https://towardsdatascience.com/are-the-new-m1-macbooks-any-good-for-data-science-lets-find-out-e61a01e8cad1