圖表重製程式|自己重畫 IOAI 所有圖
本資料夾所有圖都由這一支 Python 程式產生。複製到 Kaggle 或 Colab 執行,就能重畫、改參數、看變化。
圖表重製程式
這一頁怎麼用
- 圖不是用來背的。改一個參數重畫,看圖怎麼變,才記得住。
怎麼用
| 步驟 | 做法 |
|---|---|
| 1 | 複製下面整段程式到 Kaggle 或 Colab 的一格 |
| 2 | Colab 要先執行 !apt -y install fonts-noto-cjk,再重新啟動,中文才不會變方塊 |
| 3 | 把最後一行改成只畫你要的圖,例如 fig_gd_lr() |
| 4 | 改參數再畫一次 |
建議實驗
| 圖 | 函式 | 改什麼 | 觀察 |
|---|---|---|---|
| 梯度下降 | fig_gd_lr | 學習率改成 0.5、0.9、1.0 | 什麼時候開始震盪、什麼時候發散 |
| 過擬合 | fig_fit | 次數改成 5、9 | 幾次開始背答案 |
| 決策邊界 | fig_boundaries | K-NN 的 k 改成 1、50 | k 越小邊界越亂 |
| 分群 | fig_cluster | DBSCAN 的 eps 改成 0.1、0.5 | 太小全是雜訊,太大全併成一群 |
| L1、L2 | fig_l1l2 | 換資料集 | 哪些特徵最先變 0 |
| 卷積 | fig_conv_pool | 卷積核改成橫的 [[-1,-1,-1],[0,0,0],[1,1,1]] | 直的邊緣還找得到嗎 |
| 注意力 | fig_attention | 讓「它」改成像「墊子」 | 注意力跟著移動 |
程式(程式/make_figs.py)
完整程式(點開複製)
# IOAI 備賽圖表重製程式:python make_figs.py
# 需要:numpy、matplotlib、scikit-learn(Kaggle、Colab 已內建)
# 每個 fig_ 函式畫一張圖,存到 ../圖/
import os
import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from matplotlib import font_manager
# 中文字型:Mac 用 Arial Unicode;Colab 先執行 !apt -y install fonts-noto-cjk
for name in ['Arial Unicode MS', 'PingFang TC', 'Noto Sans CJK TC', 'Microsoft JhengHei']:
if any(f.name == name for f in font_manager.fontManager.ttflist):
plt.rcParams['font.family'] = name
break
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['figure.dpi'] = 110
try:
OUT = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '圖')
except NameError: # 在 Kaggle、Colab 的格子裡執行
OUT = '圖'
os.makedirs(OUT, exist_ok=True)
GOOD, MID, BAD = '#2e7d32', '#f9a825', '#c62828'
def save(fig, name):
fig.tight_layout()
fig.savefig(os.path.join(OUT, name), bbox_inches='tight')
plt.close(fig)
print('saved', name)
def fig_coverage():
parts = ['1 基礎與經典 ML', '2 神經網路與深度學習', '3 電腦視覺', '4 NLP 與音訊']
ok, mid, no = np.array([8, 15, 6, 2]), np.array([13, 3, 2, 2]), np.array([4, 0, 2, 3])
fig, ax = plt.subplots(figsize=(8, 3.2))
y = np.arange(len(parts))[::-1]
ax.barh(y, ok, color=GOOD, label='✓ fast.ai 夠')
ax.barh(y, mid, left=ok, color=MID, label='● 要補一點')
ax.barh(y, no, left=ok + mid, color=BAD, label='✗ 要整個補')
for i, (a, b, c) in enumerate(zip(ok, mid, no)):
for x, v in [(a / 2, a), (a + b / 2, b), (a + b + c / 2, c)]:
if v: ax.text(x, y[i], str(v), ha='center', va='center', color='white', fontsize=11, weight='bold')
ax.set_yticks(y, parts)
ax.set_xlabel('大綱小題目數量')
ax.set_title('IOAI 2026 大綱:fast.ai 涵蓋多少?(共 60 項)')
ax.legend(loc='lower right', fontsize=9)
save(fig, 'ioai_coverage.png')
def fig_lesson_stars():
lessons = ['L01', 'L02', 'L03', 'L04', 'L05', 'L06', 'L07', 'L08', 'L08A', 'L09', 'L10', 'L11', 'L12',
'L13', 'L14', 'L15', 'L16', 'L17', 'L18', 'L19', 'L20', 'L21', 'L22', 'L23', 'L24', 'L25']
stars = [3, 2, 3, 3, 3, 3, 2, 3, 1, 2, 1, 2, 2, 3, 2, 2, 1, 2, 3, 2, 1, 1, 1, 2, 3, 1]
color = {3: BAD, 2: MID, 1: '#90a4ae'}
fig, ax = plt.subplots(figsize=(10, 2.8))
ax.bar(lessons, stars, color=[color[s] for s in stars])
ax.set_yticks([1, 2, 3], ['★', '★★', '★★★'])
ax.axvline(8.5, color='gray', ls='--')
ax.text(4, 3.3, 'Part 1', ha='center'); ax.text(17, 3.3, 'Part 2', ha='center')
ax.set_ylim(0, 3.6)
ax.set_title('每一課對 IOAI 的重要度(紅色先看)')
plt.xticks(rotation=60)
save(fig, 'ioai_lesson_stars.png')
def fig_activations():
x = np.linspace(-5, 5, 200)
fig, axs = plt.subplots(1, 3, figsize=(10, 3))
for ax, (name, y, rng) in zip(axs, [
('ReLU:max(0, x)', np.maximum(0, x), '輸出 0 到 ∞'),
('Sigmoid:1 / (1 + e⁻ˣ)', 1 / (1 + np.exp(-x)), '輸出 0 到 1 → 機率'),
('Tanh', np.tanh(x), '輸出 −1 到 1')]):
ax.plot(x, y, lw=3)
ax.axhline(0, color='gray', lw=.5); ax.axvline(0, color='gray', lw=.5)
ax.set_title(name); ax.set_xlabel(rng); ax.grid(alpha=.3)
save(fig, 'ioai_activations.png')
def fig_losses():
e = np.linspace(-3, 3, 200)
p = np.linspace(0.01, 0.99, 200)
fig, axs = plt.subplots(1, 2, figsize=(10, 3.4))
axs[0].plot(e, e ** 2, lw=3, label='MSE=誤差²(大錯罰很重)')
axs[0].plot(e, np.abs(e), lw=3, label='MAE=|誤差|(不怕極端值)')
axs[0].set_xlabel('誤差=預測 − 答案'); axs[0].set_title('迴歸用'); axs[0].legend(fontsize=9); axs[0].grid(alpha=.3)
axs[1].plot(p, -np.log(p), lw=3, color=BAD)
axs[1].set_xlabel('模型給正確答案的機率 p'); axs[1].set_ylabel('−log(p)')
axs[1].set_title('分類用:交叉熵(越有把握答錯,罰越重)'); axs[1].grid(alpha=.3)
save(fig, 'ioai_losses.png')
def fig_gd_lr():
f = lambda x: x ** 2
xs = np.linspace(-3.2, 3.2, 200)
fig, axs = plt.subplots(1, 3, figsize=(11, 3.3))
for ax, (lr, title, c) in zip(axs, [(0.02, '學習率太小 0.02:走很慢', MID),
(0.3, '剛好 0.3:很快到底', GOOD),
(1.05, '太大 1.05:越跳越遠', BAD)]):
x, path = 3.0, [3.0]
for _ in range(8):
x = x - lr * 2 * x # 梯度 f'(x) = 2x
path.append(x)
path = np.array(path)
wide = lr > 1 # 發散的那格要畫寬一點才看得到
xr = np.linspace(-7, 7, 300) if wide else xs
ax.plot(xr, f(xr), color='gray')
ax.plot(path, f(path), 'o-', color=c)
for i, p in enumerate(path[:4]): ax.annotate(str(i), (p, f(p)), textcoords='offset points', xytext=(6, 4), fontsize=8)
ax.set_title(title); ax.set_ylim(0, 45 if wide else 11)
fig.suptitle('梯度下降:x ← x − 學習率 × 斜率(f(x) = x²,走 8 步)')
save(fig, 'ioai_gd_lr.png')
def fig_fit():
rng = np.random.default_rng(0)
x = np.sort(rng.uniform(0, 1, 15)); y = np.sin(2 * np.pi * x) + rng.normal(0, .2, 15)
xs = np.linspace(0, 1, 200)
fig, axs = plt.subplots(1, 3, figsize=(11, 3.2))
for ax, (deg, title) in zip(axs, [(1, '欠擬合:太簡單'), (3, '剛好'), (14, '過擬合:背答案')]):
c = np.polyfit(x, y, deg)
ax.scatter(x, y, color='k', zorder=3)
ax.plot(xs, np.clip(np.polyval(c, xs), -2, 2), lw=2, color={1: MID, 3: GOOD, 14: BAD}[deg])
ax.set_title(f'{title}({deg} 次多項式)'); ax.set_ylim(-2, 2)
save(fig, 'ioai_fit.png')
def fig_curves():
ep = np.arange(1, 31)
train = 1.2 * np.exp(-ep / 6) + .05
val = 1.2 * np.exp(-ep / 6) + .15 + .004 * np.maximum(0, ep - 10) ** 1.6
best = ep[val.argmin()]
fig, ax = plt.subplots(figsize=(7, 3.3))
ax.plot(ep, train, lw=3, label='訓練損失')
ax.plot(ep, val, lw=3, label='驗證損失')
ax.axvline(best, color=BAD, ls='--'); ax.text(best + .5, 1.0, f'早停 Early stopping\n第 {best} 輪最好', color=BAD)
ax.axvspan(best, 30, color=BAD, alpha=.07); ax.text(22, .5, '過擬合區', color=BAD)
ax.set_xlabel('epoch'); ax.set_ylabel('損失'); ax.legend(); ax.grid(alpha=.3)
ax.set_title('驗證損失開始上升=過擬合,停在最低點')
save(fig, 'ioai_curves.png')
def fig_split_cv():
fig, axs = plt.subplots(2, 1, figsize=(9, 4), gridspec_kw={'height_ratios': [1, 2.4]})
ax = axs[0]
for left, w, c, t in [(0, 70, '#1976d2', '訓練集 70%:拿來學'), (70, 15, MID, '驗證集 15%:選模型'),
(85, 15, BAD, '測試集 15%:最後看一次')]:
ax.barh(0, w, left=left, color=c); ax.text(left + w / 2, 0, t, ha='center', va='center', color='white', fontsize=9)
ax.axis('off'); ax.set_title('切資料')
ax = axs[1]
for k in range(5):
for j in range(5):
ax.barh(4 - k, 20, left=20 * j, color=MID if j == k else '#1976d2', edgecolor='white')
ax.text(101, 4 - k, f'第 {k + 1} 次', va='center')
ax.set_xlim(0, 112); ax.axis('off')
ax.set_title('5 折交叉驗證:每一份輪流當驗證集(黃),分數取平均')
save(fig, 'ioai_split_cv.png')
def fig_boundaries():
from sklearn.datasets import make_moons
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import SVC
X, y = make_moons(300, noise=.25, random_state=0)
models = [('邏輯斯迴歸:直線', LogisticRegression()), ('K-NN(k=5):看鄰居', KNeighborsClassifier(5)),
('決策樹:切方塊', DecisionTreeClassifier(max_depth=5)), ('隨機森林:很多樹投票', RandomForestClassifier(100, random_state=0)),
('SVM(RBF 核):彎曲邊界', SVC())]
xx, yy = np.meshgrid(np.linspace(-2, 3, 200), np.linspace(-1.5, 2, 200))
fig, axs = plt.subplots(1, 5, figsize=(16, 3.3))
for ax, (t, m) in zip(axs, models):
m.fit(X, y)
z = m.predict(np.c_[xx.ravel(), yy.ravel()]).reshape(xx.shape)
ax.contourf(xx, yy, z, alpha=.3, cmap='coolwarm')
ax.scatter(X[:, 0], X[:, 1], c=y, cmap='coolwarm', s=8)
ax.set_title(f'{t}\n準確率 {m.score(X, y):.2f}', fontsize=10); ax.set_xticks([]); ax.set_yticks([])
save(fig, 'ioai_boundaries.png')
def fig_cluster():
from sklearn.datasets import make_moons, make_blobs
from sklearn.cluster import KMeans, DBSCAN
Xb, _ = make_blobs(300, centers=3, random_state=1)
Xm, _ = make_moons(300, noise=.06, random_state=0)
fig, axs = plt.subplots(1, 3, figsize=(11, 3.3))
axs[0].scatter(*Xb.T, c=KMeans(3, n_init=10, random_state=0).fit_predict(Xb), cmap='viridis', s=8)
axs[0].set_title('K-Means:圓團 ✓')
axs[1].scatter(*Xm.T, c=KMeans(2, n_init=10, random_state=0).fit_predict(Xm), cmap='viridis', s=8)
axs[1].set_title('K-Means:月牙 ✗ 切錯')
axs[2].scatter(*Xm.T, c=DBSCAN(eps=.2).fit_predict(Xm), cmap='viridis', s=8)
axs[2].set_title('DBSCAN:月牙 ✓ 照密度連')
for ax in axs: ax.set_xticks([]); ax.set_yticks([])
save(fig, 'ioai_cluster.png')
def fig_pca_tsne():
from sklearn.datasets import load_digits
from sklearn.decomposition import PCA
from sklearn.manifold import TSNE
X, y = load_digits(return_X_y=True)
fig, axs = plt.subplots(1, 2, figsize=(10, 4))
for ax, (t, Z) in zip(axs, [('PCA:線性投影,快、可解釋', PCA(2).fit_transform(X)),
('t-SNE:保留鄰居,分得更開(只能看)', TSNE(2, random_state=0).fit_transform(X))]):
s = ax.scatter(*Z.T, c=y, cmap='tab10', s=5)
ax.set_title(t); ax.set_xticks([]); ax.set_yticks([])
fig.colorbar(s, ax=axs, label='數字 0–9')
fig.suptitle('手寫數字 64 維 → 2 維')
fig.savefig(os.path.join(OUT, 'ioai_pca_tsne.png'), bbox_inches='tight'); plt.close(fig); print('saved ioai_pca_tsne.png')
def fig_cm_roc():
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import confusion_matrix, roc_curve, roc_auc_score
X, y = load_breast_cancer(return_X_y=True)
Xtr, Xte, ytr, yte = train_test_split(X, y, test_size=.3, random_state=0)
m = make_pipeline(StandardScaler(), LogisticRegression()).fit(Xtr, ytr)
cm = confusion_matrix(yte, m.predict(Xte))
fig, axs = plt.subplots(1, 2, figsize=(10, 4))
ax = axs[0]
ax.imshow(cm, cmap='Blues')
labels = [['TN 真陰', 'FP 假陽'], ['FN 假陰', 'TP 真陽']]
for i in range(2):
for j in range(2):
ax.text(j, i, f'{labels[i][j]}\n{cm[i, j]}', ha='center', va='center', fontsize=12,
color='white' if cm[i, j] > cm.max() / 2 else 'black')
ax.set_xticks([0, 1], ['預測 0', '預測 1']); ax.set_yticks([0, 1], ['實際 0', '實際 1'])
ax.set_title('混淆矩陣')
p = m.predict_proba(Xte)[:, 1]
fpr, tpr, _ = roc_curve(yte, p)
axs[1].plot(fpr, tpr, lw=3, label=f'模型 AUC = {roc_auc_score(yte, p):.3f}')
axs[1].plot([0, 1], [0, 1], '--', color='gray', label='亂猜 AUC = 0.5')
axs[1].set_xlabel('假陽率 FPR'); axs[1].set_ylabel('真陽率 TPR(召回率)')
axs[1].set_title('ROC 曲線:越靠左上越好'); axs[1].legend()
save(fig, 'ioai_cm_roc.png')
def fig_l1l2():
from sklearn.datasets import load_diabetes
from sklearn.linear_model import Lasso, Ridge
from sklearn.preprocessing import StandardScaler
X, y = load_diabetes(return_X_y=True)
X = StandardScaler().fit_transform(X)
alphas = np.logspace(-2, 3.5, 60)
fig, axs = plt.subplots(1, 2, figsize=(10, 3.4))
for ax, (t, M, a) in zip(axs, [('L1(Lasso):係數一個個變成 0 → 自動挑特徵', Lasso, alphas / 30),
('L2(Ridge):係數一起縮小,不會變 0', Ridge, alphas)]):
coefs = np.array([M(alpha=v).fit(X, y).coef_ for v in a])
ax.plot(a, coefs); ax.set_xscale('log'); ax.axhline(0, color='k', lw=.5)
ax.set_xlabel('正則化強度 α →'); ax.set_ylabel('係數'); ax.set_title(t, fontsize=10)
save(fig, 'ioai_l1l2.png')
def fig_conv_pool():
img = np.array([[0, 0, 0, 9, 9, 9]] * 6)
k = np.array([[-1, 0, 1]] * 3)
conv = np.array([[(img[i:i + 3, j:j + 3] * k).sum() for j in range(4)] for i in range(4)])
pool_in = np.array([[1, 3, 2, 1], [4, 6, 5, 0], [3, 1, 1, 2], [0, 2, 7, 4]])
mx = pool_in.reshape(2, 2, 2, 2).max(axis=(1, 3))
av = pool_in.reshape(2, 2, 2, 2).mean(axis=(1, 3))
fig, axs = plt.subplots(1, 6, figsize=(16, 3), gridspec_kw={'width_ratios': [6, 3, 4, 4, 2, 2]})
for ax, (m, t) in zip(axs, [(img, '輸入 6×6\n(左暗右亮)'), (k, '卷積核 3×3\n找直的邊'),
(conv, '卷積輸出 4×4\n邊緣處數字大'), (pool_in, '池化輸入 4×4'),
(mx, '最大池化 2×2\n取每格最大'), (av, '平均池化 2×2\n取每格平均')]):
ax.imshow(m, cmap='Blues')
for (i, j), v in np.ndenumerate(m):
ax.text(j, i, f'{v:g}', ha='center', va='center', fontsize=10)
ax.set_title(t, fontsize=10); ax.set_xticks([]); ax.set_yticks([])
fig.suptitle('輸出尺寸 = (輸入 + 2×padding − kernel) ÷ stride + 1 例:(6 + 0 − 3) ÷ 1 + 1 = 4')
save(fig, 'ioai_conv_pool.png')
def fig_attention():
words = ['貓', '坐在', '墊子', '上', '它', '很', '舒服']
rng = np.random.default_rng(3)
d = 8
E = rng.normal(size=(len(words), d))
E[4] = .8 * E[0] + .2 * E[4] # 讓「它」跟「貓」很像
Q, K = E, E
s = Q @ K.T / np.sqrt(d)
A = np.exp(s) / np.exp(s).sum(1, keepdims=True)
fig, ax = plt.subplots(figsize=(5.5, 4.5))
ax.imshow(A, cmap='Reds')
ax.set_xticks(range(len(words)), words); ax.set_yticks(range(len(words)), words)
ax.set_xlabel('被注意的字(K)'); ax.set_ylabel('發問的字(Q)')
for (i, j), v in np.ndenumerate(A):
ax.text(j, i, f'{v:.2f}', ha='center', va='center', fontsize=8)
ax.set_title('注意力 = softmax(Q·K^T / √d)\n每一列加起來 = 1;「它」最注意「貓」')
save(fig, 'ioai_attention.png')
def fig_vision_tasks():
from matplotlib.patches import Rectangle
img = np.ones((60, 90, 3))
yy, xx = np.mgrid[:60, :90]
cat = (xx - 25) ** 2 + (yy - 32) ** 2 < 14 ** 2 # 圓形=貓
dog = (abs(xx - 65) < 13) & (abs(yy - 30) < 16) # 方形=狗
img[cat] = [1, .6, .2]; img[dog] = [.3, .5, 1]
fig, axs = plt.subplots(1, 3, figsize=(12, 3.2))
axs[0].imshow(img); axs[0].set_title('影像分類\n輸出:「貓」(整張圖只給一個答案)')
axs[1].imshow(img); axs[1].set_title('物件偵測(YOLO、DETR)\n輸出:每個物體的框 + 類別')
for (x, y, w, h, t, c) in [(10, 17, 30, 30, '貓 0.97', BAD), (51, 13, 28, 34, '狗 0.91', '#1565c0')]:
axs[1].add_patch(Rectangle((x, y), w, h, fill=False, lw=3, color=c)); axs[1].text(x, y - 2, t, color=c)
mask = np.zeros((60, 90)); mask[cat] = 1; mask[dog] = 2
from matplotlib.colors import ListedColormap
axs[2].imshow(mask, cmap=ListedColormap(['#eeeeee', BAD, '#1565c0'])); axs[2].set_title('影像分割(U-Net)\n輸出:每個像素的類別(灰=背景)')
for ax in axs: ax.set_xticks([]); ax.set_yticks([])
save(fig, 'ioai_vision_tasks.png')
def fig_architectures():
from matplotlib.patches import FancyBboxPatch
def box(ax, x, y, t, c='#e3f2fd', w=1.6):
ax.add_patch(FancyBboxPatch((x, y), w, .8, boxstyle='round,pad=0.05', fc=c, ec='#455a64'))
ax.text(x + w / 2, y + .4, t, ha='center', va='center', fontsize=9)
def arrow(ax, x1, y1, x2, y2):
ax.annotate('', (x2, y2), (x1, y1), arrowprops=dict(arrowstyle='->', lw=1.5))
fig, axs = plt.subplots(2, 2, figsize=(12, 6))
ax = axs[0, 0]; ax.set_title('自編碼器(L15):壓縮再還原')
box(ax, 0, 1, '圖片'); box(ax, 2.2, 1, '編碼器', '#fff3e0'); box(ax, 4.4, 1, '小向量 z', '#ffcdd2', 1.2)
box(ax, 6.2, 1, '解碼器', '#fff3e0'); box(ax, 8.4, 1, '還原圖片')
for a, b in [(1.6, 2.2), (3.8, 4.4), (5.6, 6.2), (7.8, 8.4)]: arrow(ax, a, 1.4, b, 1.4)
ax.text(5, .3, '損失=還原圖片和原圖差多少', ha='center')
ax = axs[0, 1]; ax.set_title('GAN:生成器和判別器互相競爭')
box(ax, 0, 2, '隨機雜訊'); box(ax, 2.2, 2, '生成器 G', '#fff3e0'); box(ax, 4.4, 2, '假圖片')
box(ax, 4.4, .4, '真圖片'); box(ax, 6.8, 1.2, '判別器 D', '#fff3e0'); box(ax, 9, 1.2, '真?假?', '#ffcdd2', 1.2)
for a, b, c, d in [(1.6, 2.4, 2.2, 2.4), (3.8, 2.4, 4.4, 2.4), (6, 2.4, 6.8, 1.8), (6, .8, 6.8, 1.4), (8.4, 1.6, 9, 1.6)]: arrow(ax, a, b, c, d)
ax.text(5, -.3, 'G 想騙過 D;D 想抓出假圖', ha='center')
ax = axs[1, 0]; ax.set_title('編碼器-解碼器(翻譯、Whisper)')
box(ax, 0, 1, '英文句子\n或聲音'); box(ax, 2.2, 1, '編碼器', '#fff3e0'); box(ax, 4.4, 1, '一串向量', '#ffcdd2')
box(ax, 6.6, 1, '解碼器\n一次一個字', '#fff3e0'); box(ax, 8.8, 1, '中文句子\n或文字稿')
for a, b in [(1.6, 2.2), (3.8, 4.4), (6, 6.6), (8.2, 8.8)]: arrow(ax, a, 1.4, b, 1.4)
ax.text(5, .3, '只要編碼器=BERT(理解);只要解碼器=GPT(生成)', ha='center')
ax = axs[1, 1]; ax.set_title('CLIP(L09):圖和文字放進同一個空間')
box(ax, 0, 2, '圖片'); box(ax, 2.2, 2, '圖片編碼器', '#fff3e0'); box(ax, 0, .4, '「一隻貓」'); box(ax, 2.2, .4, '文字編碼器', '#fff3e0')
box(ax, 5, 1.2, '比相似度\n(內積)', '#ffcdd2'); box(ax, 7.4, 1.2, '配對的分數高\n不配對的分數低', w=2.4)
for a, b, c, d in [(1.6, 2.4, 2.2, 2.4), (1.6, .8, 2.2, .8), (3.8, 2.4, 5, 1.8), (3.8, .8, 5, 1.4), (6.6, 1.6, 7.4, 1.6)]: arrow(ax, a, b, c, d)
for ax in axs.ravel(): ax.set_xlim(-.2, 10.4); ax.set_ylim(-.6, 3.1); ax.axis('off')
save(fig, 'ioai_architectures.png')
if __name__ == '__main__':
for fn in [fig_coverage, fig_lesson_stars, fig_activations, fig_losses, fig_gd_lr, fig_fit, fig_curves,
fig_split_cv, fig_boundaries, fig_cluster, fig_pca_tsne, fig_cm_roc, fig_l1l2, fig_conv_pool,
fig_attention, fig_vision_tasks, fig_architectures]:
fn()