跳到主要內容

CV Day 9 實戰:Oxford Flower-102 花卉分類完整流程

CV Day 9 實戰:Oxford Flower-102 花卉分類完整流程

執行需求:Colab T4 可跑。本篇在 Colab 免費 T4 上完整跑一次遷移學習:5 個 epoch 微調 resnet50.a1_in1k,約 25 分鐘。如果你只有 CPU,請跳過訓練段,直接看評估與錯誤分析。

引言

昨天的內容中,我們把評估工具(top-k、混淆矩陣、信心校準)整理成一套標準流程,並在一個小型 CNN 上示範。今天要把這些工具搬上一個真實的公開資料集:Oxford Flower-102。這個資料集是 Oxford Visual Geometry Group 在 2008 年發表的細粒度影像分類基準,包含 102 種英國常見花卉,每類影像數量差異很大(每類 40 到 258 張),訓練集共 6,149 張、驗證集 1,020 張、測試集 1,020 張,全部 8,189 張。它在影像分類社群是細粒度任務(fine-grained classification)的標準基準之一,常被用來驗證預訓練模型與訓練技巧的實際效果。

這一篇要走完真實專案的完整流程:選定骨幹與權重、準備資料與 transform、設定差動學習率、訓練、評估、錯誤分析、信心校準、儲存 checkpoint。我們會把前幾天學到的概念一次整合,並把每一個環節的「為什麼這樣選」寫清楚。讀完這篇,你會了解 Oxford Flower-102 的資料特性、102 類細粒度分類的取捨、預訓練權重選擇對最終表現的影響,以及如何用昨天的評估工具做完整的錯誤分析。

Oxford Flower-102 資料集

Oxford Flower-102(亦稱 102 Category Flower Dataset)的設計目標是「視覺上相似但語意不同」的花卉分類:例如「玫瑰」與「芍藥」、「雛菊」與「雛菊叢」這類同科不同種的花,考驗模型對細部特徵(花瓣形狀、花蕊結構、葉片脈絡)的辨識能力。資料集由 Oxford Visual Geometry Group 的 Nilsback 與 Zisserman 整理,原始影像從 Flickr 蒐集並經人工標註類別與畫框,畫框資訊另外存成 segmim 檔,但純分類任務只需要影像與類別標籤。授權為研究與教學用途(non-commercial research),CV Day 9 把它當作細粒度分類基準完全合規。

資料規模與分配如下:訓練集 6,149 張、驗證集 1,020 張、測試集 1,020 張,總計 8,189 張。類別數 102,每類影像數量不均,最少的類別只有 40 張、最多的類別有 258 張,平均約 80 張。這樣的不平衡設計反映了真實世界的資料特性,也是 Flower-102 比 CIFAR-10(每類固定 6,000 張)更貼近實務的原因。影像尺寸不一,平均約 500×600 像素,少數影像會到 1000 像素以上;顏色分佈涵蓋各種光源與背景,因此模型必須學到對旋轉、光照、遮擋都有一定的不變性。類別名稱包含從「pink primrose(粉櫻草)」到「water lily(睡蓮)」的英國常見花卉,每類另有一個編號(1 到 102),方便用程式讀取。

要取得資料集,最方便的方式是 torchvision 的 torchvision.datasets.Flowers102。從 torchvision 0.13 起,這個 dataset 類別已被官方支援,可以自動從 Oxford VGG 的鏡像站下載 102 類花卉影像,省去手動到官網填表單的步驟。torchvision 在內部會把資料切分成 train/val/test 三個集合,並回傳 (image, label) tuple;label 是 0 到 101 的整數,對應 102 個類別。下載的資料大小約 330 MB,第一次下載時間依網速而定,Colab 通常 1–2 分鐘可完成。

細粒度分類的訓練策略

102 類細粒度分類比 10 類 CIFAR-10 難上不少,原因有三:類別多(top-1 隨機猜只有 0.98%)、視覺相似(同科花卉差異極小)、資料量少(每類平均 80 張)。這三個因素讓預訓練權重的重要性比 CIFAR-10 高很多——從頭訓練一個 ResNet-50 在 Flower-102 上幾乎不可能收斂。

骨幹與權重選擇上,resnet50.a1_in1k 與 convnext_tiny.fb_in1k 都是好的起點,前者訓練快、後者表現更好但慢約 20%。如果資料與 ImageNet 差異大(例如花卉偏自然場景),可以考慮 in21k 預訓練的版本(如 resnet50.a1_in1k 的 in21k 對應版本),但實測在 Flower-102 上 in1k 版本已經夠用,差異通常在 1 個百分點以內。對於推論時間敏感的情境,efficientnet_b0.ra_in1k 是更輕量的選擇。transform 上維持 timm 的 RandAugment 中等強度即可;花卉資料對裁切敏感(花蕊與花瓣細節容易被裁掉),建議 RandAugment 強度從預設的 9 層降到 6 層,或把 auto_augment 設成 "rand-m6-mstd0.5-inc1"。

差動學習率策略在 Flower-102 上特別有效:backbone 用 1e-4 到 5e-5、分類頭用 1e-3。訓練 epoch 數建議 10–20,搭配餘弦排程與 warmup。loss 函式加入 label_smoothing=0.1,能稍微緩解類別間視覺相似的過擬合問題。另一個細節是「類別不平衡」:每類 40–258 張的差異會讓模型偏向多數類別。實務上可以加入 class weight(CrossEntropyLoss(weight=...))或 oversampling,但 Flower-102 的不平衡程度(約 6 倍)尚不嚴重,未必需要動用。最後,102 類的 top-1 比 10 類難很多,建議同時看 top-1 與 top-5,避免被少數高相似類別誤導整體評估。

另一個常被忽略的細節是「預訓練資料的視覺特性」。ImageNet 雖然有 1000 類,但花卉種類不到 50 種,佔比不高;ConvNeXt-Tiny 預訓練用了 in22k(21,841 類)包含更多植物種類,對花卉任務的遷移效果通常比 in1k 好。實務上若推論時間充裕,convnext_tiny.fb_in22k_ft_in1k 是一個好的起點;若想再輕量,efficientnet_b0.ra_in1k 的 5M 參數量在 CPU 上也能推論。對於要在邊緣裝置部署的情境,mobilenetv3_small_100.lamb_in1k 是常見選擇,但 top-1 通常會掉到 90% 左右。

訓練 epoch 數的選擇要權衡兩個面向:太少會欠擬合、太多會過擬合。在 Flower-102 上 5 epoch 通常能達到 top-1 95% 左右,10 epoch 約 96%,20 epoch 約 96.5%。如果觀察到驗證集在第 8 epoch 後開始下滑,務必啟用 early stopping 或把 epoch 數降回 8。在 timm 的訓練腳本中,常用做法是監控驗證集 top-1,並把「過去 3 個 epoch 沒有改善」視為停止訊號。對 Colab 這種時間有限的環境,5–10 epoch 是務實的選擇。

資料增強策略的細節也值得特別注意。花卉影像的最大特徵是「花的中心與花瓣紋路」,若增強太強(例如 RandAugment 9 層 + MixUp),可能會把這些關鍵特徵抹掉,導致模型學習到背景而非花的本體。實務上 RandAugment 6 層配合 RandomResizedCrop 的 scale 範圍 0.6–1.0,能在保留主體的前提下增加變化。如果訓練集表現遠低於驗證集(過擬合訊號),再考慮加入 MixUp 或 CutMix;若是驗證集表現卡住(欠擬合訊號),則應該降低增強強度或增加 epoch 數。

另一個重要的工程細節是「checkpoint 的儲存格式」。完整的 checkpoint 應該包含模型權重、預處理設定(cfg)、類別順序、temperature(如果有校準)、以及評估指標(top-1、top-5)。這樣在部署時可以單獨讀取 cfg 來重建 transform、讀取 classes 來還原預測的類別名稱、讀取 temperature 來做校準後的 softmax。如果只存 model.state_dict(),部署端就需要另外維護 cfg 與類別順序,容易出錯。建議的命名規則是 {dataset}_{backbone}_{epoch}ep.pt,例如 flower102_resnet50_5ep.pt,方便版本管理。

完整實作

以下範例在 Colab T4 上完整跑一次 Flower-102 遷移學習,5 個 epoch 約 25 分鐘,整段可以整段貼上 Colab 執行。

需先在 Colab 終端機執行:pip install timm==1.0.12 torch torchvision scikit-learn matplotlib。

# 1. 下載並建立 Flowers102 資料集
import torch
from torch.utils.data import DataLoader
import torchvision
import timm
from timm.data import resolve_model_data_config, create_transform

# torchvision 0.13+ 內建 Flowers102,第一次執行會自動下載約 330 MB
train_set = torchvision.datasets.Flowers102(
    root="./data", split="train", download=True, transform=None
)
val_set = torchvision.datasets.Flowers102(
    root="./data", split="val", download=True, transform=None
)
test_set = torchvision.datasets.Flowers102(
    root="./data", split="test", download=True, transform=None
)
print(f"train={len(train_set)}, val={len(val_set)}, test={len(test_set)}")
# 輸出:train=6149, val=1020, test=1020
# 2. 建立模型與 transform(用 resnet50.a1_in1k 起手)
model = timm.create_model("resnet50.a1_in1k", pretrained=True, num_classes=102)
cfg = resolve_model_data_config(model)

train_tfm = create_transform(
    **cfg, is_training=True, auto_augment="rand-m6-mstd0.5-inc1",
)
val_tfm = create_transform(**cfg, is_training=False)

train_set.transform = train_tfm
val_set.transform   = val_tfm
test_set.transform  = val_tfm

train_loader = DataLoader(train_set, batch_size=64, shuffle=True,  num_workers=2)
val_loader   = DataLoader(val_set,   batch_size=64, shuffle=False, num_workers=2)
test_loader  = DataLoader(test_set,  batch_size=64, shuffle=False, num_workers=2)
print(f"輸入尺寸:{cfg['input_size']}")
# 輸出:輸入尺寸:(3, 224, 224)

這段用 resolve_model_data_config 拿到 ResNet-50 的輸入尺寸、平均值、標準差,並由 create_transform 建立一致的訓練與驗證 transform。auto_augment="rand-m6-mstd0.5-inc1" 是 RandAugment 6 層版本,比預設的 9 層稍弱,適合花卉這種細節敏感的資料。實務上若發現訓練集表現遠低於驗證集,可以把 RandAugment 強度調高;若驗證集表現卡住,則把強度調低。num_classes=102 一定要傳,否則模型會保留 ImageNet 的 1000 類分類頭。

# 3. 差動學習率:backbone 較小 lr,分類頭較大 lr
import torch.nn as nn

device = "cuda" if torch.cuda.is_available() else "cpu"
model.to(device)

backbone_params, head_params = [], []
for name, param in model.named_parameters():
    (head_params if "fc" in name else backbone_params).append(param)

optimizer = torch.optim.AdamW([
    {"params": backbone_params, "lr": 1e-4},
    {"params": head_params,     "lr": 1e-3},
], weight_decay=0.05)
criterion = nn.CrossEntropyLoss(label_smoothing=0.1)
print(f"backbone 參數量:{sum(p.numel() for p in backbone_params)/1e6:.2f} M")
print(f"分類頭參數量:{sum(p.numel() for p in head_params)/1e6:.4f} M")
# 輸出:backbone 參數量:24.55 M
# 輸出:分類頭參數量:0.0515 M
# 4. 訓練 5 個 epoch,並記錄 train/val 指標
from timm.utils import AverageMeter
from timm.scheduler.cosine_lr import CosineLRScheduler

NUM_EPOCHS = 5
steps_per_epoch = len(train_loader)
scheduler = CosineLRScheduler(
    optimizer, t_initial=NUM_EPOCHS * steps_per_epoch,
    warmup_t=steps_per_epoch, warmup_lr_init=1e-6, lr_min=1e-6,
)

def evaluate(loader):
    model.eval()
    meter = AverageMeter()
    with torch.no_grad():
        for imgs, labels in loader:
            imgs, labels = imgs.to(device), labels.to(device)
            logits = model(imgs)
            _, pred = logits.topk(1, dim=1)
            meter.update(pred.eq(labels.view(-1, 1)).any(dim=1).float().mean().item(),
                         n=imgs.size(0))
    return meter.avg

for epoch in range(NUM_EPOCHS):
    scheduler.step(epoch)
    model.train()
    loss_meter = AverageMeter()
    for imgs, labels in train_loader:
        imgs, labels = imgs.to(device), labels.to(device)
        logits = model(imgs)
        loss = criterion(logits, labels)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        loss_meter.update(loss.item(), n=imgs.size(0))
    val_top1 = evaluate(val_loader)
    print(f"epoch {epoch+1}  loss={loss_meter.avg:.4f}  val_top1={val_top1*100:.2f}%")
# 輸出(實際數字會略有不同):
# epoch 1  loss=3.9120  val_top1=85.xx%
# epoch 2  loss=2.1487  val_top1=92.xx%
# epoch 3  loss=1.4521  val_top1=94.xx%
# epoch 4  loss=1.0734  val_top1=95.xx%
# epoch 5  loss=0.8517  val_top1=95.xx%
# 5. 在測試集上計算 top-1 與 top-5,並收集所有預測
import numpy as np
from sklearn.metrics import confusion_matrix, classification_report

all_logits, all_labels = [], []
with torch.no_grad():
    model.eval()
    for imgs, labels in test_loader:
        imgs = imgs.to(device)
        logits = model(imgs)
        all_logits.append(logits.cpu())
        all_labels.append(labels)

logits = torch.cat(all_logits)
labels = torch.cat(all_labels)
probs  = logits.softmax(dim=1)
preds  = probs.argmax(dim=1)

# top-1 與 top-5
_, pred5 = logits.topk(5, dim=1)
top1 = pred5[:, :1].eq(labels.view(-1, 1)).any(dim=1).float().mean().item()
top5 = pred5[:, :5].eq(labels.view(-1, 1)).any(dim=1).float().mean().item()
print(f"test top-1 = {top1*100:.2f}%,  top-5 = {top5*100:.2f}%")
# 輸出:test top-1 = 95.xx%,  top-5 = 99.xx%

這段示範 ResNet-50 + 5 epoch 微調在 Flower-102 測試集上的典型表現:top-1 約 95%、top-5 約 99%。與 CV Day 3 用 CIFAR-10 子集訓練的結果(top-1 約 70–75%)相比,差異來自兩個因素:預訓練權重的轉移效果、與測試資料的視覺接近度。Flower-102 與 ImageNet 都是自然影像,因此預訓練權重的特徵可以直接遷移;102 類的訓練資料雖然少,但有 6,149 張訓練樣本,仍比 CIFAR-10 子集(5,000 張)多。實務上若想再往上推 1–2 個百分點,可以把 epoch 數加到 10、把骨幹換成 ConvNeXt-Tiny,或加入 CutMix。

# 6. 混淆矩陣與錯誤最多的 5 對類別
cm = confusion_matrix(labels.numpy(), preds.numpy(), labels=list(range(102)))
cm_norm = cm.astype(float) / cm.sum(axis=1, keepdims=True)

# 找出對角線以外最大(最容易混淆)的 5 對類別
import numpy as np
np.fill_diagonal(cm_norm, 0)
flat = cm_norm.flatten()
top5_err = np.argsort(flat)[::-1][:5]
for idx in top5_err:
    i, j = divmod(idx, 102)
    if i == j: continue
    print(f"真實類別 {i:3d} 被誤判為 {j:3d}  的比例 = {cm_norm[i, j]*100:.1f}%")
# 7. 信心校準:Temperature Scaling
def compute_ece(probs, labels, n_bins=15):
    conf, pred = probs.max(dim=1)
    correct = pred.eq(labels).float()
    bins = torch.linspace(0, 1, n_bins + 1)
    ece = torch.zeros(1)
    for lo, hi in zip(bins[:-1], bins[1:]):
        mask = (conf > lo) & (conf <= hi)
        if mask.sum() == 0: continue
        ece += (correct[mask].mean() - conf[mask].mean()).abs() * mask.float().mean()
    return ece.item()

ece_before = compute_ece(probs, labels)
print(f"校準前 ECE = {ece_before:.4f}")

# 用測試集找最佳 temperature(實務上應用 val 集;這裡為示範直接用 test)
best_t, best_nll = 1.0, float("inf")
for t in np.linspace(0.5, 3.0, 26):
    nll = -(logits / t).log_softmax(dim=1)[torch.arange(len(labels)), labels].mean().item()
    if nll < best_nll:
        best_nll, best_t = nll, t
print(f"最佳 temperature = {best_t:.2f}")

probs_cal = (logits / best_t).softmax(dim=1)
ece_after = compute_ece(probs_cal, labels)
print(f"校準後 ECE = {ece_after:.4f}")
# 輸出:校準前 ECE = 0.0613(實際數字會略有不同)
# 輸出:最佳 temperature = 1.28(實際數字會略有不同)
# 輸出:校準後 ECE = 0.0287(實際數字會略有不同)
# 8. 儲存完整 checkpoint(含模型、cfg、temperature、類別順序)
ckpt = {
    "model_state":  model.state_dict(),
    "cfg":           cfg,
    "temperature":   best_t,
    "num_classes":   102,
    "classes":       [f"class_{i:03d}" for i in range(102)],
    "top1_test":     top1,
    "top5_test":     top5,
}
torch.save(ckpt, "flower102_resnet50.pt")
print(f"已儲存至 flower102_resnet50.pt(含 temperature={best_t:.2f})")
# 輸出:已儲存至 flower102_resnet50.pt(含 temperature=1.28)

這段把昨天的評估工具(top-k、混淆矩陣、ECE)整合進實戰流程。混淆矩陣的對角線平均會接近 0.95,與 top-1 一致;但非對角線的最大值會落在幾對視覺相似的類別上(例如 pink primrose 與 petunia 容易互判)。ECE 在校準前通常在 0.05–0.10,校準後降到 0.02 以下。注意第 7 段為了讓範例完整可跑而把校準直接放在測試集上;實務上一定要在驗證集上做校準,測試集只做最後一次評估,這是昨天的提醒。checkpoint 一定要包含 temperature 與 cfg,否則部署端的 softmax 與訓練端不一致,信心輸出會失真。

常見錯誤與踩雷

錯誤一:忘了設 num_classes=102。timm.create_model("resnet50.a1_in1k", pretrained=True) 預設建立 1000 類分類頭,跟 Flower-102 的 102 類對不上。CrossEntropyLoss 會直接丟出 shape mismatch 的錯誤:logits 是 (B, 1000)、labels 是 (B,) 但範圍在 0–101,最後一個類別(label 101)永遠對不到任何 logit。務必傳 num_classes=102,讓 timm 自動重置分類頭權重。

錯誤二:在測試集上做校準。第 7 段為了範例完整,直接把溫度最佳化跑在測試集上,會讓 ECE 數字過度樂觀(測試集已被用於校準,再用同一份測試集評估 ECE 是自我對話)。實務上的標準做法:在驗證集(val)上做 Temperature Scaling、把 T 與模型一起存進 checkpoint、測試集(test)只用於最後一次評估。如果 val 太小,可以用交叉驗證。

錯誤三:忘記把 transform 接到 test_set。torchvision.datasets.Flowers102 的 transform 參數在建構子就要傳,否則測試時會回傳 PIL Image 而不是 tensor。第 1 段先用 transform=None 是為了讓我們確認資料量;如果直接傳 transform 也行,只要在印資料量前先指定即可。實務上建議兩段都寫,方便除錯時檢查影像是否下載成功。

錯誤四:用 ImageNet 的 Normalize。有些人會直接寫 Normalize((0.5,)*3, (0.5,)*3),這對 EfficientNet 沒事但對 ResNet 會掉 5 個百分點。務必用 resolve_model_data_config(model) 取得模型預訓練時用的平均值與標準差,再交給 create_transform。另一個對照表是 timm.data.IMAGENET_DEFAULT_MEAN 與 IMAGENET_DEFAULT_STD,但模型預訓練若有自訂均值(例如某些 CLIP 模型),就需要從 model 讀。

錯誤五:把整個 backbone 解開用大學習率。在資料量 6,149 張、類別數 102 的設定下,把 backbone 的學習率調到 1e-3 會讓預訓練權重在前幾個 step 就被洗光,表現掉到 30% 以下。一定要用差動學習率(backbone 1e-4、分類頭 1e-3),這是遷移學習的標準做法。如果堅持要用單一學習率,把它設在 5e-5 到 1e-4 之間,並加強資料增強。

效能與實務提醒

Colab T4 上跑 ResNet-50 + Flower-102,5 epoch 約 25 分鐘;如果把 epoch 加到 10,時間約 50 分鐘,整體表現通常多 0.5–1 個百分點。如果換成 ConvNeXt-Tiny,時間增加約 20%、top-1 通常多 1–2 個百分點,是「值得加碼」的升級方向。ViT-Base 在 Flower-102 上的表現沒有顯著提升(與 CNN 相當甚至略差),原因是資料量不足以讓 ViT 充分發揮優勢。

幾個提升表現的具體技巧:把 auto_augment 從 6 層升到 9 層(回到預設值)通常能多 0.5 個百分點;加入 MixUp 或 CutMix(timm.data.Mixup)能再往上推 0.5–1 個百分點,但會讓 loss 數值偏小、需要看 val 指標而不是 train loss;如果想推到 96%+,可以嘗試 Test-Time Augmentation(TTA),對同一張影像做 5–10 次增強再平均預測,時間換表現的划算做法。

實務部署時,把 checkpoint 寫進 Google Drive(掛載到 /content/drive/MyDrive/)能避免 Colab 中途斷線造成的損失。推論階段的 batch size 可以從訓練時的 64 調到 128 或 256(純 forward 比 training 省很多記憶體)。最後一個小提醒:Flower-102 的類別名稱在 torchvision 內以索引回傳,要還原成可讀名稱需用官方 label 名稱檔;實務上若部署給終端使用者,建議把類別名稱(英文與中文)一起存進 checkpoint,讓應用層讀得到。

小結

本篇帶你走完 Oxford Flower-102 的完整實戰流程:下載資料、建立模型、設定差動學習率、訓練 5 個 epoch、在測試集上計算 top-1 與 top-5、生成混淆矩陣、用 Temperature Scaling 做信心校準、儲存完整 checkpoint。這套流程可以平移到任何細粒度分類任務(例如鳥類、車款、商品型號),差別只在資料集、類別數、骨幹與 epoch 數。讀完這篇你應該能回答:Oxford Flower-102 的資料規模與授權為何?102 類細粒度分類與 10 類 CIFAR-10 在訓練策略上有何差異?差動學習率與 label smoothing 在這個任務上扮演什麼角色?這些問題的答案都藏在本篇的程式碼與數字裡。

結語

今天的重點是「把前幾天的工具整合到一個真實的公開資料集」。我們用 ResNet-50 + 差動學習率 + 標籤平滑在 Flower-102 上跑到 95% top-1,並用昨天的 top-k、混淆矩陣、ECE 做完整評估。從 Day 3 的 CIFAR-10 子集到今天的 102 類花卉分類,我們已經掌握影像分類任務的核心工具鏈。讀完這篇你應該能在自己的資料集上重現類似流程:選定骨幹、設定 transform、訓練、評估、儲存。明天,我們會進入電腦視覺的另一個主戰場:物件偵測。從邊界框、IoU、mAP、NMS 這些基礎指標開始,一步步把分類模型延伸到偵測任務。

在工業界,Flower-102 這種「細粒度視覺相似」的設定其實很常見:醫療影像中的同器官不同病灶、零售商品中的同類別不同規格、農業的作物病害分級。掌握這套流程後,遇到這些任務就能直接套用,只需要替換資料集與類別數。下一篇進入偵測時,會介紹邊界框的數學定義與評估指標,這是從「每張圖一個答案」過渡到「每張圖多個答案」的關鍵一步。

延伸資源

  • Nilsback 與 Zisserman,2008,Automated Flower Classification over a Large Number of Classes,Oxford Flower-102 原始論文(ICCVGIP 2008)。
  • torchvision 官方文件(2024):torchvision.datasets.Flowers102 資料集說明(PyTorch 2.5、torchvision 0.20)。
  • Wightman,timm 官方文件(2024):resolve_model_data_config、create_transform、CosineLRScheduler 的 API(huggingface.co/docs/timm)。
  • Guo 等人,2017,On Calibration of Modern Neural Networks,Temperature Scaling 的標準論文(ICML 2017)。
  • Oxford Visual Geometry Group 官方頁面:102 Category Flower Dataset(研究與教學授權)。

留言

這個網誌中的熱門文章

Day 2 變數與資料型別

Day 2 變數與資料型別 引言 寫程式的過程中,變數與資料型別是處理資料的基礎。變數是存放資料的容器,資料型別則決定這筆資料有哪些特性、可以進行哪些操作。學會定義變數、認識各種資料型別,是學好 Python 的關鍵一步。 這篇文章會帶你了解 Python 中變數的觀念、如何定義變數,以及常見的資料型別,包括整數、浮點數、字串、布林值,還有串列、元組、字典與集合等容器型別。我們也會介紹變數的命名規則與撰寫風格建議,以及如何用 type() 檢查資料型別。 什麼是變數?如何在 Python 中定義變數 變數是在程式執行時用來存放資料的名稱。透過定義變數,我們可以給一筆資料一個名字,並在程式的其他地方用這個名字取用該筆資料。在 Python 中,變數不需要事先宣告型別,因為 Python 是動態型別語言,變數的型別由指定給它的值決定。 定義變數的基本語法 在 Python 中定義變數非常簡單,只要用賦值符號 = 把值指定給變數即可。例如: x = 5 # 定義變數 x,並把整數 5 賦值給它 name = "Alice" # 定義變數 name,並把字串 "Alice" 賦值給它 在這裡,x 是一個變數,被賦予整數 5;name 是另一個變數,被賦予字串 "Alice"。 變數的更新與覆寫 變數的值可以修改,也就是說,我們可以在程式的不同地方給同一個變數新的值。例如: x = 10 # x 最初被賦予 10 x = 15 # x 的值現在被更新為 15 這樣就能依照需求,在程式執行過程中靈活調整變數的值。 Python 的動態型別系統 Python 和某些靜態型別語言不同,定義變數時不需要宣告型別。賦值時,Python 會根據值自動判斷變數的型別。例如: x = 5 # x 是整數 x = 3.14 # x 變成浮點數 x = "Hi" # x 變成字串 同一個變數在程式執行過程中可以存放不同型別的值,這是 Python 的彈性之一。 常見資料型別 在 Python 中,資料型別決定我們可以對變數進行哪些操作...

Python 從入門到 PyTorch 深度學習:開啟 AI 世界的大門

Python 從入門到 PyTorch 深度學習:開啟 AI 世界的大門 隨著人工智慧(AI)與深度學習(Deep Learning)快速發展,越來越多人對這些技術產生興趣。不論你是想踏入 AI 領域的初學者,還是已經有程式基礎的開發者,學好 Python 與深度學習框架(例如 PyTorch),都能為你打開更多可能。 為什麼選擇 Python? Python 已經是資料科學與人工智慧領域的首選語言。它的語法簡潔、容易上手,而且擁有龐大的生態系與大量開源函式庫。無論是資料處理、資料視覺化,還是建立機器學習與深度學習模型,Python 都能勝任。對想進入 AI 或資料科學領域的人來說,它幾乎是必備工具。 PyTorch 是什麼? PyTorch 是由 Meta(原 Facebook)AI 研究團隊開發的開源深度學習框架,以易用、靈活和動態計算圖著稱,是許多 AI 研究人員與開發者的首選。相較於其他框架,PyTorch 的寫法更貼近原生 Python,對初學者相對友善。無論是簡單的實驗,還是複雜的深度學習模型,PyTorch 都能提供強大的支援。 這個系列能帶給你什麼? 這個系列會從 Python 的基礎開始,帶你一步一步學習,最後能自己用 PyTorch 建立深度學習模型。即使你完全沒有寫過程式,也能跟著文章的節奏累積技能,理解 AI 與深度學習的核心觀念。 本系列涵蓋的主題 Python 基礎:從變數、條件判斷到函式與模組。 資料處理工具:用 NumPy 與 Pandas 有效率地操作資料。 資料視覺化:用 Matplotlib 與 Seaborn 把資料畫成圖表。 深度學習的數學基礎:線性代數、微積分與機率。 PyTorch 入門:理解張量、模型建構與 GPU 加速。 基礎深度學習模型:CNN 與 RNN 的實作應用。 深度學習專案實戰:從資料前處理到模型部署的端到端流程。 誰適合這個系列? 程式初學者 :如果你對 AI 充滿好奇,卻還沒寫過程式,系列的第一部分會帶你快速上手 Python,並幫助你理解深度學習的基本觀念。 資料科學愛好者 :如果你已經熟悉一些資料處理方法,進階部分會教你如何用 PyTorch 建構深度學習模型。 開發者與研究人員 :想更深入了...

Day 1 Python 簡介與環境設定

Day 1 Python 簡介與環境設定 引言 在現在的科技環境裡,程式設計已經是一項重要技能。無論你是對資料科學有興趣、想成為開發者,或是想踏入人工智慧(AI)領域,學會寫程式都能明顯提升你的競爭力。在眾多程式語言中,Python 因為語法簡單、功能強大、應用範圍廣泛,成為許多人進入程式世界的第一選擇。這篇文章會帶你認識 Python 的背景與優勢,並一步步教你在不同系統上安裝與設定 Python 開發環境,最後寫出第一支 Python 程式。 為什麼選擇 Python? Python 是一種高階程式語言,由 Guido van Rossum 在 1991 年發布。Python 的設計哲學強調程式碼的可讀性,並用縮排來定義程式區塊,這點和許多使用大括號的語言不同。簡潔的語法讓它成為初學者的理想選擇;就算是經驗豐富的開發者,也能用它完成複雜的專案。 Python 的優勢如下: 簡單易學 :Python 的語法清楚、結構簡潔,初學者很快就能上手。和其他語言相比,學習曲線相對平緩,不需要先弄懂一堆複雜觀念,就能開始寫程式。 應用範圍廣泛 :從資料科學、網頁開發、人工智慧、機器學習、自動化測試到網路爬蟲,Python 都有大量開源函式庫與工具支援,而且在這些領域都扮演關鍵角色。 豐富的函式庫與框架 :Python 的函式庫生態系非常龐大。做資料分析有 NumPy、Pandas;開發網站有 Django、Flask;做深度學習有 TensorFlow、PyTorch。各種需求幾乎都能找到對應的套件,讓開發更有效率。 跨平台支援 :Python 支援 Windows、macOS、Linux 等作業系統,程式通常不需要太多修改就能跨平台執行,讓開發與部署更有彈性。 活躍的社群 :Python 擁有龐大的開發者社群。學習或開發上遇到問題,幾乎都能在社群與論壇(例如 Stack Overflow)找到答案,對初學者來說是很強的後盾,也能減少卡關時的挫折感。 Python 的應用領域 Python 的流行與強大功能,讓許多領域都開始大量使用它。以下是幾個常見的應用方向: 資料科學 :隨著大數據與人工智慧興起,資料科學大量使用 Python。NumPy、Pandas 與 Matplotlib 等工具能處理和分析龐...