圖表重製程式

🏠 IOAI 總覽 | ← 圖解速查

這一頁怎麼用

  • 圖不是用來背的。改一個參數重畫,看圖怎麼變,才記得住。

怎麼用

步驟做法
1複製下面整段程式到 Kaggle 或 Colab 的一格
2Colab 要先執行 !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_boundariesK-NN 的 k 改成 1、50k 越小邊界越亂
分群fig_clusterDBSCAN 的 eps 改成 0.1、0.5太小全是雜訊,太大全併成一群
L1、L2fig_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()

🏠 IOAI 總覽 | ← 圖解速查

Built with LogoFlowershow