Chương 4·Bài 4.1

Sử dụng model pretrained

Bài 1Kiểm SHA-256

Trước khi nạp một tệp trọng số tải về, phải chắc nó đúng là tệp mình mong đợi. torch.load có thể chạy mã trong tệp, nên một tệp bị sửa hay bị thay không được phép nạp.

Mỗi test có một tệp candidate.pt và mã SHA-256 mong đợi. Hãy tính SHA-256 trên các byte của tệp, so với mã mong đợi, và báo kích thước tệp. Một nửa số test có tệp đã bị sửa đúng một byte. Không gọi torch.load khi mã không khớp.

Khớp mã chỉ chứng tỏ tệp giống hệt bản đã ghi nhận, không chứng tỏ tệp ấy an toàn hay tốt.

Dữ liệu vào

Mỗi thư mục test có candidate.pt và input.json chứa expected_sha256.

Kết quả

Một đối tượng JSON gồm matches (true hoặc false) và bytes (số byte của tệp).

Chấm điểm

Có 20 test, mỗi test 5 điểm.

Ví dụ

Input mẫu

{
  "expected_sha256": "aca5591b9429317876c78fd4cc874708eb8a7487b22dfbc855707948fd167a02"
}

Output mẫu

{"matches": true, "bytes": 20667}

Bài 2Chạy offline

Bộ kit có sẵn một model nhỏ đã học để nhận các chữ số 00 tới 55 từ ảnh 8×88\times8: assets/pretrained.pt, kèm phiếu mô tả assets/ASSET.json. Không cần Internet.

Model gồm Linear(64, 32), ReLU, Linear(32, 6), kiểu float64. Tệp pretrained.pt là một từ điển với các khóa encoder_weight, encoder_bias, head_weight, head_bias và feature_divisor.

  1. Kiểm SHA-256 của pretrained.pt với trường sha256 trong ASSET.json trước khi nạp.
  2. Nạp bằng torch.load(..., map_location="cpu", weights_only=True), dựng model, chép trọng số, chuyển sang eval.
  3. Chia các điểm ảnh (từ 00 tới 1616) cho feature_divisor một lần, rồi chạy model theo từng batch batch_size hàng, kể cả batch cuối nhỏ hơn.

Dữ liệu vào

Mỗi tệp input.json gồm X (mỗi hàng 6464 điểm ảnh) và batch_size. Model nằm ở assets/ trong bộ kit.

Kết quả

Một đối tượng JSON {"logits": [...]}, mỗi hàng sáu số, theo đúng thứ tự hàng của X.

Chấm điểm

Có 20 test, mỗi test 5 điểm. Số thực được chấm với sai số khoảng 10−710^{-7}.

Ví dụ

Input mẫu

{
  "X": [
    [
      0.0, 0.0, 6.0, 12.0, 11.0, 0.0, 0.0, 0.0, 0.0, 0.0, 12.0, 16.0,
      15.0, 0.0, 0.0, 0.0, 0.0, 0.0, 13.0, 16.0, 14.0, 2.0, 0.0, 0.0,
      0.0, 1.0, 15.0, 16.0, 11.0, 2.0, 0.0, 0.0, 0.0, 0.0, 9.0, 16.0,
      10.0, 0.0, 0.0, 0.0, 0.0, 0.0, 9.0, 16.0, 14.0, 5.0, 0.0, 0.0,
      0.0, 0.0, 10.0, 16.0, 16.0, 14.0, 0.0, 0.0, 0.0, 0.0, 4.0, 11.0,
      12.0, 8.0, 0.0, 0.0
    ],
    [
      0.0, 0.0, 0.0, 1.0, 11.0, 12.0, 0.0, 0.0, 0.0, 0.0, 0.0, 9.0,
      13.0, 1.0, 0.0, 0.0, 0.0, 0.0, 8.0, 15.0, 3.0, 0.0, 0.0, 0.0,
      0.0, 2.0, 16.0, 6.0, 1.0, 5.0, 2.0, 0.0, 0.0, 12.0, 13.0, 8.0,
      13.0, 16.0, 9.0, 0.0, 0.0, 16.0, 16.0, 13.0, 11.0, 16.0, 6.0,
      0.0, 0.0, 3.0, 4.0, 0.0, 11.0, 14.0, 0.0, 0.0, 0.0, 0.0, 0.0,
      1.0, 16.0, 12.0, 0.0, 0.0
    ],
    [
      0.0, 0.0, 3.0, 15.0, 16.0, 12.0, 0.0, 0.0, 0.0, 0.0, 6.0, 16.0,
      6.0, 14.0, 6.0, 0.0, 0.0, 0.0, 0.0, 3.0, 1.0, 15.0, 6.0, 0.0,
      0.0, 0.0, 0.0, 1.0, 14.0, 16.0, 3.0, 0.0, 0.0, 5.0, 8.0, 2.0,
      13.0, 16.0, 3.0, 0.0, 0.0, 5.0, 16.0, 0.0, 0.0, 9.0, 13.0, 0.0,
      0.0, 1.0, 15.0, 11.0, 8.0, 12.0, 16.0, 1.0, 0.0, 0.0, 3.0, 14.0,
      16.0, 16.0, 9.0, 0.0
    ],
    [
      0.0, 2.0, 10.0, 14.0, 11.0, 1.0, 0.0, 0.0, 0.0, 7.0, 15.0, 8.0,
      16.0, 4.0, 0.0, 0.0, 0.0, 1.0, 1.0, 6.0, 15.0, 1.0, 0.0, 0.0,
      0.0, 0.0, 0.0, 15.0, 9.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 16.0,
      15.0, 9.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 6.0, 15.0, 8.0, 0.0,
      0.0, 2.0, 8.0, 4.0, 6.0, 15.0, 7.0, 0.0, 0.0, 2.0, 13.0, 16.0,
      15.0, 9.0, 0.0, 0.0
    ],
    [
      0.0, 1.0, 15.0, 16.0, 4.0, 0.0, 0.0, 0.0, 0.0, 9.0, 16.0, 11.0,
      14.0, 0.0, 0.0, 0.0, 0.0, 12.0, 10.0, 5.0, 16.0, 0.0, 0.0, 0.0,
      0.0, 4.0, 7.0, 8.0, 13.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 15.0,
      6.0, 0.0, 0.0, 0.0, 0.0, 0.0, 5.0, 16.0, 2.0, 0.0, 0.0, 0.0, 0.0,
      4.0, 15.0, 14.0, 10.0, 11.0, 12.0, 1.0, 0.0, 0.0, 13.0, 16.0,
      16.0, 15.0, 11.0, 1.0
    ],
    [
      0.0, 0.0, 12.0, 16.0, 16.0, 8.0, 0.0, 0.0, 0.0, 3.0, 16.0, 13.0,
      8.0, 5.0, 0.0, 0.0, 0.0, 2.0, 16.0, 3.0, 0.0, 0.0, 0.0, 0.0, 0.0,
      0.0, 16.0, 13.0, 9.0, 0.0, 0.0, 0.0, 0.0, 0.0, 10.0, 16.0, 16.0,
      7.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 10.0, 13.0, 0.0, 0.0, 0.0,
      0.0, 2.0, 11.0, 16.0, 10.0, 0.0, 0.0, 0.0, 0.0, 11.0, 16.0, 12.0,
      0.0, 0.0, 0.0
    ],
    [
      0.0, 1.0, 12.0, 12.0, 12.0, 15.0, 6.0, 0.0, 0.0, 1.0, 14.0, 5.0,
      5.0, 4.0, 1.0, 0.0, 0.0, 0.0, 12.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
      8.0, 16.0, 16.0, 15.0, 8.0, 0.0, 0.0, 0.0, 1.0, 4.0, 4.0, 5.0,
      12.0, 7.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 11.0, 4.0, 0.0, 0.0,
      2.0, 7.0, 2.0, 10.0, 12.0, 0.0, 0.0, 0.0, 2.0, 16.0, 15.0, 8.0,
      1.0, 0.0, 0.0
    ]
  ],
  "batch_size": 1
}

Output mẫu

{
  "logits": [
    [
      -5.807707779701959, 6.262389991542139, -0.1805818126488483,
      -5.405650393044603, -2.914198224595852, -4.05130910836966
    ],
    [
      -0.6624765413643406, -0.8836470824124462, -12.53123415477641,
      -6.283162381462738, 10.43438515488338, -1.9497023920343306
    ],
    [
      2.386387562913321, -5.956173236139999, 3.5783709884966277,
      8.065934096445043, -9.279591469392177, -7.129724098740805
    ],
    [
      -6.986298259044535, -3.70525622678644, -1.4967837980752114,
      11.211807528777143, -8.637818951471965, -0.11231706346611894
    ],
    [
      -5.087163543112431, -0.03251758889801304, 12.701459477358622,
      -2.283476536327855, -10.438661585057954, -3.3804756506158107
    ],
    [
      -3.75175212687943, -4.717251673102867, -9.247914182069762,
      1.794691598467062, -4.577260297076585, 7.9901169302428645
    ],
    [
      -2.759484102438518, -5.954105898463277, -11.874341775979428,
      -0.24440528644877196, -2.805945002963199, 13.154425632411423
    ]
  ]
}

Bài 3Ảnh chữ số

Lần này đầu vào là ảnh PNG thật: các chữ số viết tay 8×88\times8 của bộ dữ liệu UCI, ảnh xám với độ sáng từ 00 đến 240240. Dùng lại model của bài B.

Model đã học trên điểm ảnh từ 00 tới 1616 chia cho 1616, tức thang [0,1][0,1]. Ảnh PNG ở đây có thang 00 tới 240240, nên phải chia cho 240240 để đưa về đúng thang ấy, không chia cho feature_divisor. Đọc từng ảnh theo thứ tự trong image_names, trải thành 6464 số theo từng hàng, chia cho 240240, chạy model và lấy lớp có logit lớn nhất.

Dữ liệu vào

Mỗi thư mục test có images/ và input.json chứa image_names. Model nằm ở assets/ trong bộ kit.

Kết quả

Một đối tượng JSON {"predictions": [...]}, theo thứ tự của image_names.

Chấm điểm

Có 20 test, mỗi test 5 điểm. Một test được điểm khi accuracy từ 0.850.85 trở lên.

Bài 4Đếm ResNet

ResNet-50 là một backbone pretrained rất hay dùng. Trước khi tải trọng số, nên biết nó có bao nhiêu tham số và mỗi tầng cho ra tensor shape gì. Bài này tính các con số ấy bằng tay, không dựng model, cho cả họ ResNet kiểu bottleneck với số block mỗi tầng tùy chọn.

Kiến trúc theo torchvision. Mọi conv không có bias; mỗi BatchNorm có 2C2C tham số với CC kênh. Conv k×kk\times k từ cinc_{in} kênh sang coutc_{out} kênh có cincoutk2c_{in}c_{out}k^2 tham số và cho kích thước không gian ⌊h+2p−ks⌋+1\left\lfloor\frac{h+2p-k}{s}\right\rfloor+1 với stride ss, padding pp.

  1. Thân đầu: conv 7×77\times7, 3→643\to64 kênh, stride 22, padding 33; BatchNorm; ReLU; max pooling 3×33\times3, stride 22, padding 11 (không có tham số).
  2. Bốn tầng, tầng ss có layers[s-1] block và độ rộng w=64⋅2s−1w=64\cdot2^{s-1}. Mỗi block gồm conv 1×11\times1 sang ww kênh; conv 3×33\times3 w→ww\to w, padding 11; conv 1×11\times1 w→4ww\to4w; mỗi conv có một BatchNorm theo sau. Block đầu của mỗi tầng có thêm nhánh tắt: conv 1×11\times1 sang 4w4w kênh cùng một BatchNorm. Ở block đầu của tầng 22, 33, 44, conv 3×33\times3 và conv của nhánh tắt có stride 22; mọi chỗ khác stride 11.
  3. Đầu ra: average pooling toàn cục, rồi Linear(2048, num_classes) có bias.

Ảnh đầu vào có 33 kênh, kích thước image_size × image_size. Hãy tính:

  • parameters: tổng số tham số học được.
  • stage_shapes: shape [kênh, cao, rộng] của đầu ra mỗi tầng, không tính chiều batch.
  • block_conv_params: tổng tham số của các conv (không tính BatchNorm) trong block query_block = [s, i], tức block thứ ii (đánh từ 00) của tầng ss, kể cả conv nhánh tắt nếu có.

Dữ liệu vào

Một đối tượng JSON gồm layers (bốn số), num_classes, image_size và query_block.

Kết quả

Một đối tượng JSON gồm parameters, stage_shapes và block_conv_params.

Giới hạn

  • Mỗi tầng từ 11 đến 66 block, image_size từ 3232 đến 224224.

Chấm điểm

Có 20 test, mỗi test 5 điểm.

Ví dụ

Input mẫu

{
  "layers": [3, 4, 6, 3],
  "num_classes": 1000,
  "image_size": 224,
  "query_block": [3, 2]
}

Output mẫu

{
  "parameters": 25557032,
  "stage_shapes": [[256, 56, 56], [512, 28, 28], [1024, 14, 14], [2048, 7, 7]],
  "block_conv_params": 1114112
}

Bài 5Model card

Một model pretrained không chỉ là tệp trọng số. Nó còn đi kèm cách tiền xử lý đầu vào và danh sách tên lớp, ghi trong model card. Dùng sai tiền xử lý, model vẫn chạy và vẫn cho ra nhãn, chỉ là nhãn sai.

Mỗi ảnh là một lưới H×WH\times W điểm, mỗi điểm ba số từ 00 đến 255255 theo thứ tự R, G, B như trong tệp ảnh. Model card cho:

  • channel_order: thứ tự kênh model mong đợi, RGB hoặc BGR. Với BGR, kênh 00 là B, kênh 22 là R.
  • scale: chia mọi giá trị cho số này.
  • mean, std: với kênh cc (theo thứ tự model mong đợi), lấy (x/scale−meanc)/stdc(x/\text{scale}-\text{mean}_c)/\text{std}_c.
  • labels: tên lớp theo thứ tự đầu ra.

Sau khi tiền xử lý, trải ảnh thành vector theo thứ tự kênh, rồi hàng, rồi cột (tức tensor (C, H, W) trải phẳng). Head tuyến tính cho logits z=Wx+bz=Wx+b, nhãn là tên của lớp có logit lớn nhất.

Hãy tính, với từng ảnh: vector đầu vào sau tiền xử lý, logits, nhãn. Thêm nhãn mà ta sẽ nhận nếu bỏ qua model card: giữ thứ tự RGB và đưa thẳng giá trị 00 tới 255255 vào head.

Dữ liệu vào

Một đối tượng JSON gồm card, images, head_weight (KK hàng, mỗi hàng 3HW3HW số) và head_bias.

Kết quả

Một đối tượng JSON gồm inputs, logits, labels và naive_labels, mỗi trường một phần tử cho mỗi ảnh.

Giới hạn

  • Không quá 55 ảnh, mỗi ảnh không quá 3×33\times3 điểm. Không có hai logit nào sát nhau.

Chấm điểm

Có 20 test, mỗi test 5 điểm. Số thực được chấm với sai số khoảng 10−710^{-7}.

Ví dụ

Input mẫu

{
  "card": {
    "scale": 255.0,
    "mean": [0.5, 0.5, 0.5],
    "std": [0.25, 0.25, 0.25],
    "channel_order": "BGR",
    "labels": ["cat", "dog"]
  },
  "images": [[[[255, 0, 0]]], [[[0, 0, 255]]], [[[128, 64, 32]]]],
  "head_weight": [[1.0, 0.0, 0.0], [0.0, 0.0, 1.0]],
  "head_bias": [0.0, 0.1]
}

Output mẫu

{
  "inputs": [
    [-2.0, -2.0, 2.0],
    [2.0, -2.0, -2.0],
    [-1.4980392156862745, -0.996078431372549, 0.007843137254901933]
  ],
  "logits": [[-2.0, 2.1], [2.0, -1.9], [-1.4980392156862745, 0.10784313725490194]],
  "labels": ["dog", "cat", "dog"],
  "naive_labels": ["cat", "dog", "cat"]
}