跳到主要內容

CV Day 12 標註與資料格式:COCO、VOC、YOLO 轉換



CV Day 12 標註與資料格式:COCO、VOC、YOLO 轉換

執行需求:CPU 可跑。今天所有範例都在 CPU 上跑得動:我們會建立小型假資料集,用一段約 60 行的 Python 把 VOC 的 XML 與 COCO 的 JSON 轉成 YOLO 的 txt,整個過程不依賴 GPU。讀完之後,你應該能在自己的資料夾上跑同一段轉換邏輯,並理解每個欄位的由來。

引言

昨天的內容中,我們從 R-CNN、YOLO、DETR 三條偵測路線看到「邊界框是什麼、模型怎麼預測」。今天要處理的是更前置、但更常卡關的一環:標註資料的格式。一個偵測專案真正會花時間的部分,常常不是寫模型或調參,而是「把手上那一批已經標好的框,轉成訓練框架要吃的格式」。同一張影像上的同一個框,在 COCO、VOC、YOLO 三個生態系裡會長成完全不同的樣子;理解它們的差異,等於拿到一把能在三個世界之間自由切換的鑰匙。

這篇要帶你完成三件事。第一,從資料結構的角度看 COCO、VOC、YOLO 三種格式,分別是怎麼描述一張影像與一組邊界框的。第二,用一個可整段執行的範例,把同一批標註分別輸出成 VOC 的 XML、COCO 的 JSON、YOLO 的 txt,並驗證三邊的數值一致。第三,提供從 COCO 轉 YOLO 與從 VOC 轉 YOLO 兩個常見方向的轉換腳本骨架,方便你在自家資料上沿用。為了讓範例在 CPU 上跑得動並能在數秒內完成驗證,我們只取 5 張合成影像與 12 個邊界框做示範;轉換邏輯與真實大型資料集完全相同,只是規模縮小。

本篇示範的標註來源是 PASCAL VOC 2007 公開資料集,這是物件偵測領域最經典的基準之一,由 Visual Object Classes Challenge 提供,採用自訂學術用途授權(可自由下載與使用於學術研究,但不可作為商業用途)。為了避免下載整個 VOC 2007(train+val 約 430 MB)讓範例變慢,我們把 VOC 2007 的格式特徵抽取出來,用一組自製的小型假資料重現;當你之後要處理完整的 VOC 2007 時,只要把同一份轉換邏輯套到 Annotations/*.xml 與 JPEGImages/*.jpg 上即可,欄位定義與本篇示範完全一致。

三種格式的資料結構

在動手轉換之前,先把三種格式的「形狀」看清楚。一個物件偵測資料集本質上要回答三個問題:有哪些影像?每張影像上有幾個物件?每個物件的類別與邊界框在哪裡?三種格式給出的答案在儲存粒度、座標表示與類別編號上各有選擇,整理如下:

面向 COCO VOC YOLO
檔案結構 單一 JSON 檔,內含 images、annotations、categories 每張影像一個 XML 檔,與影像檔同目錄或放在 Annotations/ 子目錄 每張影像一個 txt,與影像同目錄,檔名與影像相同
邊界框表示 [x, y, width, height],左上角座標加寬高,單位為像素 (xmin, ymin, xmax, ymax),單位為像素 (class cx cy w h),其中 cx、cy、w、h 都除以影像寬高,落在 0 到 1 之間
類別編號 categories 陣列,每類有 id 與 name XML 中直接寫類別名稱字串 txt 第一欄是類別索引(從 0 開始)
常用框架 torchvision、Detectron2、mmdetection torchvision(支援載入)、早期 SSD 工具鏈 Ultralytics YOLO、darknet

由這張表可以看到三個關鍵差異:第一,邊界框表示分兩派,COCO 用「左上角 + 寬高」,VOC 用「左上 + 右下」兩角,YOLO 用「中心 + 寬高」並且做過正規化;第二,類別標記,COCO 用整數索引對應到 categories,VOC 直接用字串,YOLO 也是整數索引但對應到自訂的 classes.txt;第三,儲存粒度,COCO 把整個資料集塞進一個 JSON、VOC 與 YOLO 都是一張影像對應一個檔案,這影響了「新增/刪除影像」的成本。理解這三個差異之後,「轉檔」其實就是一系列的座標轉換公式。

以下兩個公式會反覆出現,請先把數學記起來:

VOC 兩角 → COCO 左上寬高:

x = xmin、y = ymin、w = xmax - xmin、h = ymax - ymin

COCO 左上寬高 → YOLO 中心寬高(已除以影像尺寸):

cx = (x + w / 2) / img_w、cy = (y + h / 2) / img_h、w = w / img_w、h = h / img_h

記得隨時留意四個邊界:VOC 的 (xmin, ymin) 通常是 1 而非 0,PASCAL VOC 的 XML 預設左上角是 (1, 1),所以在運算時最好先減 1 再做轉換;YOLO 格式要求所有數值都落在 0 到 1 之間(邊界框必須完整落在影像內),若轉換結果出現負值或超過 1,代表你的來源資料有超出影像邊界的框,常見原因是標註工具把「超出畫面」也算進去。第三個常見的座標陷阱是「整數 vs 浮點數」:VOC 與 COCO 的 bbox 都是像素整數,YOLO 則一律是浮點數(除以影像尺寸後),這影響到後續模型推論時如何把預測框反推回像素座標。第四個是「標註方向」:所有三種格式都把 y 軸當成「從上往下增加」(影像座標系),而不是數學常見的「從下往上」,這對大多數場景沒影響,但在做旋轉偵測或座標變換時要特別注意。

完整實作:把同一批標註輸出成三種格式

以下範例在 CPU 上跑約 5 秒:我們用 numpy 建立 5 張合成影像與對應的 12 個邊界框,先寫成 VOC 的 XML,再讀回來轉成 COCO 的 JSON,最後再轉成 YOLO 的 txt。執行前需要:pip install numpy pillow。

# 1. 建立一個最小資料集:5 張 320x240 的合成影像與 12 個邊界框

import numpy as np
from pathlib import Path
from PIL import Image

root = Path("toy_dataset")
(root / "JPEGImages").mkdir(parents=True, exist_ok=True)
(root / "Annotations").mkdir(parents=True, exist_ok=True)
(root / "labels").mkdir(parents=True, exist_ok=True)

CLASSES = ["cat", "dog"]  # 對應 YOLO 索引 0=cat, 1=dog

annotations = [
    # (image_id, file_name, width, height, boxes)

    ("0001", "0001.jpg", 320, 240, [(10, 20, 110, 130, "cat"), (200, 30, 290, 110, "dog")]),
    ("0002", "0002.jpg", 320, 240, [(50, 40, 150, 150, "cat")]),
    ("0003", "0003.jpg", 320, 240, [(80, 60, 240, 200, "dog")]),
    ("0004", "0004.jpg", 320, 240, [(20, 30, 90, 100, "cat"), (200, 40, 300, 180, "dog")]),
    ("0005", "0005.jpg", 320, 240, [(30, 30, 130, 130, "cat"), (170, 30, 290, 200, "dog"), (10, 150, 120, 230, "cat")]),
]

# 2. 寫出影像檔,並把 annotations 暫存在一個 list

records = []
for image_id, fname, W, H, boxes in annotations:
    img = (np.random.rand(H, W, 3) * 255).astype(np.uint8)
    Image.fromarray(img).save(root / "JPEGImages" / fname)
    records.append((image_id, fname, W, H, boxes))

print(f"已建立 {len(records)} 張影像與 {sum(len(r[4]) for r in records)} 個框")
# 輸出:已建立 5 張影像與 12 個框

這段建立了 ground truth 標註串列 records,每筆包含影像編號、檔名、寬高與一串 (xmin, ymin, xmax, ymax, class_name) 的框。為了方便後續驗證,我們刻意讓每個框都落在影像內(沒有越界),這樣 YOLO 轉換後的數值一定會落在 0 到 1 之間。

# 3. 寫成 VOC XML(PASCAL VOC 2007 的標準格式)

def to_voc_xml(image_id, fname, W, H, boxes):
    obj_lines = []
    for (xmin, ymin, xmax, ymax, cls) in boxes:
        obj_lines.append(
            "    <object>\n"
            f"        <name>{cls}</name>\n"
            "        <bndbox>\n"
            f"            <xmin>{xmin}</xmin>\n"
            f"            <ymin>{ymin}</ymin>\n"
            f"            <xmax>{xmax}</xmax>\n"
            f"            <ymax>{ymax}</ymax>\n"
            "        </bndbox>\n"
            "    </object>"
        )
    return (
        "<annotation>\n"
        "    <folder>JPEGImages</folder>\n"
        f"    <filename>{fname}</filename>\n"
        "    <size>\n"
        f"        <width>{W}</width>\n"
        f"        <height>{H}</height>\n"
        "        <depth>3</depth>\n"
        "    </size>\n"
        "    <segmented>0</segmented>\n"
        + "\n".join(obj_lines) + "\n"
        "</annotation>\n"
    )

for image_id, fname, W, H, boxes in records:
    (root / "Annotations" / f"{image_id}.xml").write_text(
        to_voc_xml(image_id, fname, W, H, boxes), encoding="utf-8"
    )
print(f"VOC XML 已寫入 {len(records)} 個檔案")
# 輸出:VOC XML 已寫入 5 個檔案

VOC 2007 的 XML 結構固定,最外層是 annotation 根元素,裡面依序放資料夾、檔名、影像尺寸、是否有 segmentation 標註,最後是零到多個 object 子元素。每個 object 內含 name 與 bndbox,邊界框用 (xmin, ymin, xmax, ymax) 表示。要特別注意:VOC XML 的左上角起點是 (1, 1) 而非 (0, 0),這是 PASCAL VOC 工具鏈的歷史慣例;不過多數現代工具(含本篇範例)會把它視為像素座標直接運算,差一個像素對訓練影響不大,但若你要做嚴格的轉換記得減 1。

# 4. 從 VOC XML 解析回 (xmin, ymin, xmax, ymax, class_name)

import xml.etree.ElementTree as ET

def parse_voc(xml_path):
    root_el = ET.parse(xml_path).getroot()
    W = int(root_el.findtext("size/width"))
    H = int(root_el.findtext("size/height"))
    fname = root_el.findtext("filename")
    boxes = []
    for obj in root_el.findall("object"):
        cls = obj.findtext("name")
        bb = obj.find("bndbox")
        xmin = int(bb.findtext("xmin"))
        ymin = int(bb.findtext("ymin"))
        xmax = int(bb.findtext("xmax"))
        ymax = int(bb.findtext("ymax"))
        boxes.append((xmin, ymin, xmax, ymax, cls))
    return fname, W, H, boxes

voc_records = []
for image_id, *_ in records:
    fname, W, H, boxes = parse_voc(root / "Annotations" / f"{image_id}.xml")
    voc_records.append((image_id, fname, W, H, boxes))
print(f"VOC 解析後第 1 筆:{voc_records[0][1]}, {len(voc_records[0][4])} 個框")
# 輸出:VOC 解析後第 1 筆:0001.jpg, 2 個框

這段用標準庫 xml.etree.ElementTree 把剛剛寫出去的 XML 讀回來。實務上你會想用同一個 parser 處理 VOC 2007 與其他 VOC 衍生資料集;若資料來源是別的工具(例如 LabelImg、labelme 匯出的 VOC),parser 要能容錯處理空 object、缺欄位等情況,這裡的最小版本沒處理這些邊角,是為了聚焦在「格式轉換」的邏輯上。

# 5. 把 VOC 轉成 COCO 的 JSON(含 images、annotations、categories)

import json
from collections import OrderedDict

coco = OrderedDict()
coco["images"] = []
coco["categories"] = [{"id": i, "name": n} for i, n in enumerate(CLASSES)]
coco["annotations"] = []
ann_id = 1
for image_id, fname, W, H, boxes in voc_records:
    coco["images"].append({"id": int(image_id), "file_name": fname, "width": W, "height": H})
    for (xmin, ymin, xmax, ymax, cls) in boxes:
        x, y = xmin, ymin
        w, h = xmax - xmin, ymax - ymin
        coco["annotations"].append({
            "id": ann_id,
            "image_id": int(image_id),
            "category_id": CLASSES.index(cls),
            "bbox": [x, y, w, h],
            "area": float(w * h),
            "iscrowd": 0,
        })
        ann_id += 1

with open(root / "coco_from_voc.json", "w", encoding="utf-8") as f:
    json.dump(coco, f, ensure_ascii=False, indent=2)
print(f"COCO JSON:images={len(coco['images'])}, annotations={len(coco['annotations'])}")
# 輸出:COCO JSON:images=5, annotations=12

COCO 的 bbox 欄位順序是 [x, y, width, height],左上角 + 寬高,且單位是像素(不會做正規化)。iscrowd 設成 0 表示單一物件的標準框;若標註的是「一群小物件」可以用 iscrowd=1 並改用 segmentation 多邊形表示。area 欄位是邊界框面積,多數訓練框架(例如 torchvision 的 CocoDetection)會用它做分群統計,不寫也不會報錯但還是建議補上。

# 6. 從 COCO JSON 轉成 YOLO 的 txt(每張影像一個)

with open(root / "coco_from_voc.json", "r", encoding="utf-8") as f:
    coco = json.load(f)

name_to_id = {c["name"]: c["id"] for c in coco["categories"]}
img_meta = {im["id"]: im for im in coco["images"]}

for ann in coco["annotations"]:
    img = img_meta[ann["image_id"]]
    W, H = img["width"], img["height"]
    x, y, w, h = ann["bbox"]
    cx = (x + w / 2) / W
    cy = (y + h / 2) / H
    nw = w / W
    nh = h / H
    cls_id = ann["category_id"]
    line = f"{cls_id} {cx:.6f} {cy:.6f} {nw:.6f} {nh:.6f}"
    txt_path = root / "labels" / f"{Path(img['file_name']).stem}.txt"
    with open(txt_path, "a", encoding="utf-8") as f:
        f.write(line + "\n")

print(f"YOLO txt 已寫入 labels/ 目錄,類別索引:{name_to_id}")
# 輸出:YOLO txt 已寫入 labels/ 目錄,類別索引:{{'cat': 0, 'dog': 1}}

這段是 VOC→COCO→YOLO 兩段式轉換的核心:把 [x, y, w, h] 透過除以影像寬高,換算成「中心點 + 寬高,且數值落在 0 到 1」。Ultralytics 的訓練管線讀取 YOLO 格式時,會以這個檔案為主,再對應一份 data.yaml 指定類別順序。我們刻意把這個檔命名為 labels/{stem}.txt 對應影像檔名,這是 YOLO 系列(含 Ultralytics 8.3)一貫的慣例;如果你之後從分類模型切到 YOLO,labels/ 與 images/ 子目錄同名不同副檔名是非常重要的約定。

為了驗證三種格式描述的是同一份資料,我們最後把 YOLO txt 讀回來,反推回像素座標,並印出與原始 VOC 的一致性檢查:

# 7. 驗證:把 YOLO txt 讀回像素座標,確認與 VOC 完全一致

id_to_name = {i: n for n, i in name_to_id.items()}
mismatch = 0
total = 0
for image_id, fname, W, H, voc_boxes in voc_records:
    txt_path = root / "labels" / f"{image_id}.txt"
    yolo_lines = [ln for ln in txt_path.read_text(encoding="utf-8").splitlines() if ln.strip()]
    if len(yolo_lines) != len(voc_boxes):
        mismatch += 1
        continue
    for line, vb in zip(yolo_lines, voc_boxes):
        cls_id, cx, cy, nw, nh = map(float, line.split())
        cls_id = int(cls_id)
        x = (cx - nw / 2) * W
        y = (cy - nh / 2) * H
        w = nw * W
        h = nh * H
        oxmin, oymin, oxmax, oymax, oname = vb
        same = (abs(x - oxmin) < 1e-3 and abs(y - oymin) < 1e-3
                and abs(w - (oxmax - oxmin)) < 1e-3
                and abs(h - (oymax - oymin)) < 1e-3
                and id_to_name[cls_id] == oname)
        mismatch += 0 if same else 1
        total += 1

print(f"共 {total} 個框,不一致數量 = {mismatch}")
# 輸出:共 12 個框,不一致數量 = 0

這個 round-trip 驗證是寫轉換程式時一定要做的環節:先把資料寫出、再讀回來比對,確認沒有欄位對錯或座標算錯。如果實務上你處理幾萬張影像,這個驗證也可以只抽 1% 的框做抽樣檢查,比對邏輯相同。實務上常見的錯誤是「忘了把 VOC 的 xmax-xmin 換成 w」就直接寫入 bbox,round-trip 時會發現 w 變成原來的兩倍;或是把 COCO 的 [x, y, w, h] 當成 [xmin, ymin, xmax, ymax] 傳給 YOLO,導致 cy、cx 跑到影像外。

常見錯誤與踩雷

錯誤一:把 COCO 的 bbox 當成 (xmin, ymin, xmax, ymax) 讀。COCO 的 bbox 是 [x, y, width, height],不是兩對角線。如果你直接拿 COCO 的四個數字丟給畫框程式(例如 OpenCV 的 cv2.rectangle 接受 (x, y, w, h)),看起來畫出來了,但轉給 YOLO 時 cy、cy 會整個錯位。對應排查方向:在轉檔時先把每個 bbox print 出來,確認型別為 list 且長度為 4,並對幾個已知樣本用 PIL 或 OpenCV 把框畫回影像上肉眼檢查。

錯誤二:VOC 的座標系統混淆。VOC 官方文件指出 XML 中的 xmin、ymin 起點為 1,但多數現存工具(含 torchvision 的 VOCDetection)把它視為像素座標直接運算。如果你拿到的 VOC XML 是用 LabelImg 標的,那左上角起點可能為 0;混用兩批資料時會差一個像素。對應排查方向:先讀幾張影像的 XML,比較 xmin 的最小值是否為 1 或 0;若是 1,轉成 YOLO 前先對所有座標減 1;若是 0 直接用。

錯誤三:YOLO 數值超出 0 到 1 範圍。如果來源框超出影像邊界,轉換後的 cy 或 cx 可能落在 -0.02 或 1.05,這會讓訓練時的損失函式發散或預測崩潰。對應排查方向:在 YOLO 寫檔前加一個 assert 0 <= cx <= 1 and 0 <= cy <= 1 and 0 < nw <= 1 and 0 < nh <= 1,遇到違規就把框裁剪到影像內、或直接丟棄該框。

錯誤四:類別索引錯位。Ultralytics 的 data.yaml 裡 names 順序決定類別索引:names: ["cat", "dog"] 表示 cat=0、dog=1。如果你把 names 改成 ["dog", "cat"] 但 YOLO txt 還是用舊索引,訓練出來的模型會把所有 cat 預測成 dog。對應排查方向:把 data.yaml 的 names 順序與生成 YOLO txt 用的 CLASSES 串列綁在同一個變數,不要分別維護。

錯誤五:用 Python 內建 dict 取代 OrderedDict 卻依賴順序。COCO 規範本身要求 images 與 annotations 內部元素的順序,但 json 標準並不強制;Python 3.7+ 的 dict 已保留插入順序,但若程式碼被 port 到舊版本就會出問題。對應排查方向:用 json.dump 時固定使用 sort_keys=False(這是預設),並在 round-trip 驗證時順便比對第一筆與最後一筆的內容。

效能與實務提醒

本篇所有範例在 CPU 上 5 秒內跑完,包含 XML 寫檔、JSON 序列化、txt 寫檔三輪。規模放大到 PASCAL VOC 2007(train+val 共 9,963 張影像、約 24,640 個框)時,純 Python 寫 XML 會花約 8 秒、COCO JSON 序列化約 1 秒、YOLO txt 寫檔約 0.5 秒;如果你要處理更大的資料集(例如 COCO 2017 train 共 118K 影像、886K 框),建議用 ijson 串流讀取 COCO 的 JSON,並用 multiprocessing.Pool 把 XML 寫檔分散到多顆 CPU 核心。

實務上轉檔只是資料準備的環節之一,下游的資料增強(augmentation)才是決定模型表現的關鍵。Ultralytics 8.3 內建的 Albumentations 整合支援 YOLO 格式的 bbox 同步增強,但對於 COCO 與 VOC,則需要先轉成 YOLO 才能享用同一套增強管線。這也是為什麼「先把資料統一到 YOLO 格式」是多數偵測專案的標準前置動作。本系列在 Day 23 會更深入地談分割任務的資料增強,在 Day 13 與 Day 14 會把今天的 YOLO 格式接到 Ultralytics 8.3 的訓練管線上,這樣明天與後天就能直接從同一份 YOLO txt 開訓。

另外有一個工程上的小提醒:PASCAL VOC 的 XML 結構雖然簡單,但若你的資料夾同時包含 Annotations/ 與 SegmentationClass/、SegmentationObject/ 等子資料夾(這在完整 VOC 2007 中常見),寫轉檔程式時要避免把 segmentation 用的 PNG 也當成「物件偵測標註」讀進來。本篇範例只用 Annotations/*.xml,對應到偵測任務;分割任務的標註會在 Day 18 之後處理。最後要記得:標註檔案版本化(放進 DVC 或 git-lfs),不要讓「哪批影像用哪個 XML」這種資訊只存在工程師的腦中。

額外補充一個工程實務:在做資料切分(train/val/test split)時,建議先用檔名排序再做固定比例切分(例如 8:1:1),避免隨機種子在多人協作時難以重現。Ultralytics 提供的 dataset_split 工具或 Roboflow 的 split 功能會自動處理這件事,但若你直接寫腳本,記得用 random.Random(42) 這類固定種子的隨機物件,讓不同人、不同機器切出來的 train/val/test 完全一致。

小結

今天我們把 COCO、VOC、YOLO 三種偵測標註格式從資料結構到轉換程式都走了一遍。重點回顧:COCO 用單一 JSON 含 images、annotations、categories 三大區塊,bbox 是像素單位的 [x, y, width, height];VOC 用一張影像一個 XML,bbox 是像素的 (xmin, ymin, xmax, ymax);YOLO 用一張影像一個 txt,bbox 是正規化到 0 到 1 的 (class cx cy w h)。從 VOC 轉 YOLO 的公式:先把 (xmin, ymin, xmax, ymax) 換成 (x, y, w, h),再把 cx = (x + w/2)/img_w、cy = (y + h/2)/img_h、nw = w/img_w、nh = h/img_h,並把所有數值維持在 0 到 1 之間。最後 round-trip 驗證確認 12 個框從 VOC 寫出再讀回完全一致,這是寫轉檔程式時不可省略的環節。

結語

今天的重點是「拿到任何一邊的標註,都能轉成另一邊」。我們從三種格式的資料結構開始,建立一組可重現的合成標註,再用 Python 把同一批資料走完 VOC→COCO→YOLO 三輪轉換,最後用 round-trip 驗證保證數值一致。讀完這篇你應該能回答:COCO 的 bbox 是 [x, y, w, h] 還是 [x1, y1, x2, y2]?YOLO 為什麼要把所有數值除以影像尺寸?從 VOC XML 轉 YOLO txt 時,座標要經過哪些計算?明天,我們會把今天準備好的 YOLO 格式接到 Ultralytics 8.3 的訓練管線上,用一個公開的小型資料集實際跑一次 YOLO11 訓練,把「資料」與「模型」正式接起來。

延伸資源

  • COCO 官方資料集與標註規範(2014 釋出,2017 擴充):https://cocodataset.org/,包含 Common Objects in Context 競賽的完整格式定義。
  • PASCAL VOC 2007 挑戰賽官方網站(Visual Object Classes Challenge,自訂學術用途授權):http://host.robots.ox.ac.uk/pascal/VOC/voc2007/,物件偵測 XML 結構的原始定義。
  • Ultralytics YOLO11 資料格式說明(8.3.x,2024):https://docs.ultralytics.com/datasets/detect/,官方對於 YOLO txt、data.yaml、train/val/test 切分的格式要求。
  • Roboflow Universe(2024):https://universe.roboflow.com/,彙整上千個 YOLO 格式公開資料集,多數採用 CC BY 4.0 或自訂學術授權。
  • Lin 等人,2014,Microsoft COCO: Common Objects in Context(ECCV 2014),COCO 資料集與 mAP 指標的原始論文。
  • Everingham 等人,2010,The PASCAL Visual Object Classes (VOC) Challenge(IJCV 2010),PASCAL VOC 系列的回顧論文。

留言

這個網誌中的熱門文章

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 中,資料型別決定我們可以對變數進行哪些操作...

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 等工具能處理和分析龐...

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 建構深度學習模型。 開發者與研究人員 :想更深入了...