.. raw:: html
.. raw:: html
.. raw:: html
.. _sec_kaggle_house:
Dự đoán Giá Nhà trên Kaggle
===========================
.. raw:: html
Trong phần trước, chúng tôi đã giới thiệu những công cụ cơ bản để xây
dựng mạng học sâu và kiểm soát năng lực của nó thông qua việc giảm chiều
dữ liệu, suy giảm trọng số và dropout. Giờ bạn đã sẵn sàng để ứng dụng
tất cả những kiến thức này vào thực tiễn bằng cách tham gia một cuộc thi
trên Kaggle. `Dự đoán giá
nhà `__
là một bài toán tuyệt vời để bắt đầu: dữ liệu tương đối khái quát, không
có cấu trúc cứng nhắc nên không đòi hỏi những mô hình đặc biệt như các
bài toán có dữ liệu ảnh và âm thanh. Tập dữ liệu này được thu thập bởi
Bart de Cock vào năm 2011 :cite:`De-Cock.2011`, lớn hơn rất nhiều so
với `tập dữ liệu giá nhà
Boston `__
nổi tiếng của Harrison và Rubinfeld (1978). Nó có nhiều mẫu và đặc trưng
hơn, chứa thông tin về giá nhà ở Ames, Indiana trong khoảng thời gian từ
2006-2010.
.. raw:: html
Trong mục này, chúng tôi sẽ hướng dẫn bạn một cách chi tiết các bước
tiền xử lý dữ liệu, thiết kế mô hình, lựa chọn và điều chỉnh siêu tham
số. Chúng tôi mong rằng thông qua việc thực hành, bạn sẽ có thể quan sát
được tác động của việc kiểm soát năng lực mô hình, trích xuất đặc trưng,
v.v. trong thực tiễn. Kinh nghiệm này rất quan trọng để bạn có được trực
giác của một nhà khoa học dữ liệu.
Tải và Lưu trữ Bộ dữ liệu
-------------------------
.. raw:: html
Trong suốt cuốn sách chúng ta sẽ cần tải và thử nghiệm nhiều mô hình
trên các tập dữ liệu khác nhau. Ta sẽ lập trình một số hàm tiện ích để
hỗ trợ cho việc tải dữ liệu. Đầu tiên, ta cần khởi tạo một từ điển
``DATA_HUB`` nhằm ánh xạ một xâu ký tự đến đường dẫn (URL) với SHA-1 của
tệp tại đường dẫn đó, trong đó SHA-1 dùng để xác minh tính toàn vẹn của
tệp. Các tập dữ liệu này được lưu trữ trên trang ``DATA_URL``.
.. code:: python
import os
from mxnet import gluon
import zipfile
import tarfile
# Saved in the d2l package for later use
DATA_HUB = dict()
# Saved in the d2l package for later use
DATA_URL = 'http://d2l-data.s3-accelerate.amazonaws.com/'
.. raw:: html
.. raw:: html
.. raw:: html
Hàm ``download`` dưới đây tải tập dữ liệu có tên ``name`` từ đường dẫn
tương ứng và lưu trữ nó tại bộ nhớ cục bộ (mặc định tại ``../data``).
Nếu tệp trên đã tồn tại trong bộ nhớ đệm và SHA-1 của nó khớp với tệp
trong ``DATA_HUB``, tệp trong bộ nhớ đệm sẽ được sử dụng luôn mà không
cần phải tải lại. Điều này nghĩa là bạn chỉ cần tải tập dữ liệu đúng một
lần khi có kết nối mạng. Hàm ``download`` trả về tên của tệp được tải
xuống.
.. code:: python
# Saved in the d2l package for later use
def download(name, cache_dir='../data'):
"""Download a file inserted into DATA_HUB, return the local filename."""
assert name in DATA_HUB, "%s doesn't exist" % name
url, sha1 = DATA_HUB[name]
d2l.mkdir_if_not_exist(cache_dir)
return gluon.utils.download(url, cache_dir, sha1_hash=sha1)
.. raw:: html
Chúng ta cũng lập trình thêm hai hàm khác: một hàm để tải và giải nén
tệp zip/tar, và hàm còn lại để tải tất cả các file từ ``DATA_HUB`` (chứa
phần lớn các tập dữ liệu được sử dụng trong cuốn sách này) về bộ nhớ
đệm. Bạn có thể sử dụng hàm thứ hai để tải tất cả các tập dữ liệu này
trong cùng một lần tải nếu kết nối mạng của bạn chậm.
.. code:: python
# Saved in the d2l package for later use
def download_extract(name, folder=None):
"""Download and extract a zip/tar file."""
fname = download(name)
base_dir = os.path.dirname(fname)
data_dir, ext = os.path.splitext(fname)
if ext == '.zip':
fp = zipfile.ZipFile(fname, 'r')
elif ext == '.tar' or ext == '.gz':
fp = tarfile.open(fname, 'r')
else:
assert False, 'Only zip/tar files can be extracted'
fp.extractall(base_dir)
if folder:
return base_dir + '/' + folder + '/'
else:
return data_dir + '/'
# Saved in the d2l package for later use
def download_all():
"""Download all files in the DATA_HUB"""
for name in DATA_HUB:
download(name)
.. raw:: html
.. raw:: html
.. raw:: html
Kaggle
------
.. raw:: html
`Kaggle `__ là một nền tảng phổ biến cho các
cuộc thi học máy. Nó kết hợp dữ liệu, mã lập trình và người dùng cho cả
mục đích hợp tác và thi thố. Mặc dù việc cạnh tranh trên bảng xếp hạng
nhiều khi vượt khỏi tầm kiểm soát, ta không thể không nhắc đến sự khách
quan mà nền tảng mang lại từ việc so sánh định lượng một cách công bằng
và trực tiếp giữa phương pháp của bạn với các phương pháp của đối thủ.
Thêm vào đó, bạn còn có thể xem mã nguồn ở các lần nộp bài của (một vài)
đối thủ, nghiên cứu phương pháp của họ để biết thêm các kỹ thuật mới.
Nếu bạn muốn tham gia một cuộc thi, bạn cần đăng ký một tài khoản như
trong :numref:`fig_kaggle` (hãy làm ngay đi!).
.. raw:: html
.. _fig_kaggle:
.. figure:: ../img/kaggle.png
:width: 400px
Trang web Kaggle
.. raw:: html
Trên trang Dự Đoán Giá Nhà (*House Prices Prediction*) được mô tả ở
:numref:`fig_house_pricing`, bạn có thể tìm được tập dữ liệu (dưới
thanh “Data”), nộp kết quả dự đoán và xem thứ hạng của bạn, v.v. Đường
dẫn:
https://www.kaggle.com/c/house-prices-advanced-regression-technique
.. raw:: html
.. _fig_house_pricing:
.. figure:: ../img/house_pricing.png
:width: 400px
Dự đoán Giá Nhà
.. raw:: html
.. raw:: html
.. raw:: html
Truy cập và Đọc Bộ dữ liệu
--------------------------
.. raw:: html
Lưu ý rằng dữ liệu của cuộc thi được tách thành tập huấn luyện và tập
kiểm tra. Mỗi tập dữ liệu bao gồm giá tiền của ngôi nhà và các thuộc
tính liên quan bao gồm loại đường phố, năm xây dựng, kiểu mái nhà, tình
trạng tầng hầm, v.v. Các đặc trưng được biểu diễn bởi nhiều kiểu dữ
liệu. Ví dụ, năm xây dựng được biểu diễn bởi số nguyên, kiểu mái nhà là
đặc trưng hạng mục rời rạc, còn các đặc trưng khác thì được biểu diễn
bởi số thực dấu phẩy động (*floating point number*). Và đây là khi ta
đối mặt với vấn đề thực tiễn: ở một vài mẫu, dữ liệu bị thiếu và được
đơn thuần chú thích là ‘na’. Giá của mỗi căn nhà chỉ được cung cấp trong
tập huấn luyện (sau cùng thì đây vẫn là một cuộc thi). Bạn có thể chia
nhỏ tập huấn luyện để tạo tập kiểm định, tuy nhiên bạn sẽ chỉ biết được
chất lượng mô hình trên tập kiểm tra chính thức khi tải kết quả dự đoán
của mình lên và nhận điểm sau đó. Thanh “Data” trên cuộc thi có đường
dẫn để tải bộ dữ liệu về.
.. raw:: html
Chúng ta sẽ đọc và xử lý dữ liệu với ``pandas``, một `công cụ phân tích
dữ liệu hiệu quả `__, vì
vậy hãy đảm bảo rằng bạn đã cài đặt ``pandas`` trước khi tiếp tục. Một
điều may mắn là, nếu bạn đang sử dụng Jupyter, bạn có thể cài đặt pandas
mà không cần thoát khỏi notebook.
.. code:: python
# If pandas is not installed, please uncomment the following line:
# !pip install pandas
%matplotlib inline
from d2l import mxnet as d2l
from mxnet import autograd, init, np, npx
from mxnet.gluon import nn
import pandas as pd
npx.set_np()
.. raw:: html
Để thuận tiện, chúng ta sẽ tải và lưu tập dữ liệu giá nhà Kaggle từ
trang web ``DATA_URL``. Với những cuộc thi Kaggle khác, có thể bạn sẽ
phải tải dữ liệu về theo cách thủ công.
.. code:: python
# Saved in the d2l package for later use
DATA_HUB['kaggle_house_train'] = (
DATA_URL + 'kaggle_house_pred_train.csv',
'585e9cc93e70b39160e7921475f9bcd7d31219ce')
# Saved in the d2l package for later use
DATA_HUB['kaggle_house_test'] = (
DATA_URL + 'kaggle_house_pred_test.csv',
'fa19780a7b011d9b009e8bff8e99922a8ee2eb90')
.. raw:: html
Ta sử dụng Pandas để nạp lần lượt hai tệp csv chứa dữ liệu huấn luyện và
kiểm tra.
.. code:: python
train_data = pd.read_csv(download('kaggle_house_train'))
test_data = pd.read_csv(download('kaggle_house_test'))
.. raw:: html
Tập huấn luyện chứa :math:`1,460` mẫu, :math:`80` đặc trưng, và
:math:`1` nhãn. Tập kiểm tra chứa :math:`1,459` mẫu và :math:`80` đặc
trưng.
.. code:: python
print(train_data.shape)
print(test_data.shape)
.. parsed-literal::
:class: output
(1460, 81)
(1459, 80)
.. raw:: html
Hãy cùng xem xét 4 đặc trưng đầu tiên, 2 đặc trưng cuối cùng và nhãn
(giá nhà) của 4 mẫu đầu tiên:
.. code:: python
print(train_data.iloc[0:4, [0, 1, 2, 3, -3, -2, -1]])
.. parsed-literal::
:class: output
Id MSSubClass MSZoning LotFrontage SaleType SaleCondition SalePrice
0 1 60 RL 65.0 WD Normal 208500
1 2 20 RL 80.0 WD Normal 181500
2 3 60 RL 68.0 WD Normal 223500
3 4 70 RL 60.0 WD Abnorml 140000
.. raw:: html
Có thể thấy với mỗi mẫu, đặc trưng đầu tiên là ID. Điều này giúp mô hình
xác định được từng mẫu. Mặc dù việc này khá thuận tiện, nó không mang
bất kỳ thông tin nào cho mục đích dự đoán. Do đó chúng ta sẽ lược bỏ nó
ra khỏi tập dữ liệu trước khi đưa vào mạng nơ-ron.
.. code:: python
all_features = pd.concat((train_data.iloc[:, 1:-1], test_data.iloc[:, 1:]))
.. raw:: html
.. raw:: html
.. raw:: html
.. raw:: html
.. raw:: html
Tiền xử lý Dữ liệu
------------------
.. raw:: html
Như đã nói ở trên, chúng ta có rất nhiều kiểu dữ liệu. Trước khi đưa dữ
liệu vào mạng học sâu, ta cần thực hiện một số phép xử lý. Hãy bắt đầu
với các đặc trưng số học. Trước hết ta thay thế các giá trị còn thiếu
bằng giá trị trung bình. Đây là chiến lược hợp lý nếu các đặc trưng bị
thiếu một cách ngẫu nhiên. Để đưa tất cả đặc trưng số học về cùng một
khoảng giá trị, ta thực hiện chuyển đổi để chúng có trung bình bằng
không và phương sai đơn vị bằng cách:
.. math:: x \leftarrow \frac{x - \mu}{\sigma}.
.. raw:: html
Để kiểm tra xem công thức trên có chuyển đổi :math:`x` thành dữ liệu với
trung bình bằng không hay không, ta có thể tính
:math:`E[(x-\mu)/\sigma] = (\mu - \mu)/\sigma = 0`. Để kiểm tra phương
sai ta tính :math:`E[(x-\mu)^2] = \sigma^2`, như vậy biến chuyển đổi sẽ
có phương sai đơn vị. Lý do của việc “chuẩn hóa” dữ liệu là để đưa tất
cả các đặc trưng về cùng một độ lớn. Vì sau cùng, chúng ta không thể
*biết trước* được đặc trưng nào là đặc trưng quan trọng.
.. code:: python
numeric_features = all_features.dtypes[all_features.dtypes != 'object'].index
all_features[numeric_features] = all_features[numeric_features].apply(
lambda x: (x - x.mean()) / (x.std()))
# After standardizing the data all means vanish, hence we can set missing
# values to 0
all_features[numeric_features] = all_features[numeric_features].fillna(0)
.. raw:: html
Tiếp theo chúng ta sẽ xử lý các giá trị rời rạc như biến ‘MSZoning’. Ta
sẽ thay thế chúng bằng biểu diễn one-hot theo đúng cách mà ta đã chuyển
đổi dữ liệu phân loại đa lớp thành vector chứa :math:`0` và :math:`1`.
Ví dụ, ‘MSZoning’ bao gồm các giá trị ‘RL’ và ‘RM’, tương ứng lần lượt
với vector :math:`(1, 0)` and :math:`(0, 1)`. Việc này được thực hiện
một cách tự động trong pandas.
.. code:: python
# Dummy_na=True refers to a missing value being a legal eigenvalue, and
# creates an indicative feature for it
all_features = pd.get_dummies(all_features, dummy_na=True)
all_features.shape
.. parsed-literal::
:class: output
(2919, 331)
.. raw:: html
Bạn có thể thấy sự chuyển đổi này làm tăng số lượng các đặc trưng từ 79
lên 331. Cuối cùng, thông qua thuộc tính ``values``, ta có thể trích
xuất định dạng NumPy từ khung dữ liệu Pandas và chuyển đổi nó thành biểu
diễn ``ndarray`` gốc của MXNet dành cho mục đích huấn luyện.
.. code:: python
n_train = train_data.shape[0]
train_features = np.array(all_features[:n_train].values, dtype=np.float32)
test_features = np.array(all_features[n_train:].values, dtype=np.float32)
train_labels = np.array(train_data.SalePrice.values,
dtype=np.float32).reshape(-1, 1)
.. raw:: html
.. raw:: html
.. raw:: html
Huấn luyện
----------
.. raw:: html
Để bắt đầu, ta sẽ huấn luyện một mô hình tuyến tính với hàm mất mát bình
phương. Tất nhiên là mô hình tuyến tính sẽ không thể thắng cuộc thi
được, nhưng nó vẫn cho ta một phép kiểm tra sơ bộ để xem dữ liệu có chứa
thông tin ý nghĩa hay không. Nếu mô hình này không thể đạt chất lượng
tốt hơn việc đoán mò, khả năng cao là ta đang có lỗi trong quá trình xử
lý dữ liệu. Còn nếu nó hoạt động, mô hình tuyến tính sẽ đóng vai trò như
một giải pháp nền, giúp ta hình dung khoảng cách giữa một mô hình đơn
giản và các mô hình tốt nhất hiện có, cũng như mức độ cải thiện mà ta
mong muốn từ các mô hình “xịn” hơn.
.. code:: python
loss = gluon.loss.L2Loss()
def get_net():
net = nn.Sequential()
net.add(nn.Dense(1))
net.initialize()
return net
.. raw:: html
Với giá nhà (hay giá cổ phiếu), ta quan tâm đến các đại lượng tương đối
hơn các đại lượng tuyệt đối. Cụ thể hơn, ta thường quan tâm đến lỗi
tương đối :math:`\frac{y - \hat{y}}{y}` hơn lỗi tuyệt đối
:math:`y - \hat{y}`. Ví dụ, nếu dự đoán giá một ngôi nhà ở Rural Ohio bị
lệch đi 100,000 đô-la, mà giá thông thường một ngôi nhà ở đó là 125,000
đô-la, có lẽ mô hình đang làm việc rất kém. Mặt khác, nếu ta có cùng độ
lệch như vậy khi dự đoán giá nhà ở Los Altos Hills, California (giá nhà
trung bình ở đây tầm hơn 4 triệu đô), có thể dự đoán này lại rất chính
xác.
.. raw:: html
Một cách để giải quyết vấn đề này là tính hiệu của log giá trị dự đoán
và log giá trị thật sự. Thực ra đây chính là phép đo lỗi chính thức được
sử dụng trong cuộc thi để đánh giá chất lượng của các lần nộp bài. Sau
cùng, một giá trị :math:`\delta` bằng :math:`\log y - \log \hat{y}` nhỏ
đồng nghĩa với việc
:math:`e^{-\delta} \leq \frac{\hat{y}}{y} \leq e^\delta`. Điều này dẫn
đến hàm mất mát sau:
.. math:: L = \sqrt{\frac{1}{n}\sum_{i=1}^n\left(\log y_i -\log \hat{y}_i\right)^2}.
.. code:: python
def log_rmse(net, features, labels):
# To further stabilize the value when the logarithm is taken, set the
# value less than 1 as 1
clipped_preds = np.clip(net(features), 1, float('inf'))
return np.sqrt(2 * loss(np.log(clipped_preds), np.log(labels)).mean())
.. raw:: html
Khác với các mục trước, hàm huấn luyện ở đây sử dụng bộ tối ưu Adam (một
biến thể của SGD mà chúng tôi sẽ mô tả cụ thể hơn sau này). Lợi thế
chính của Adam so với SGD nguyên bản là: nó không quá nhạy cảm với tốc
độ học ban đầu, mặc dù kết quả cũng không tốt hơn (đôi khi còn tệ hơn)
SGD nếu tài nguyên để tối ưu siêu tham số là vô hạn. Bộ tối ưu này sẽ
được mô tả cụ thể hơn trong :numref:`chap_optimization`.
.. code:: python
def train(net, train_features, train_labels, test_features, test_labels,
num_epochs, learning_rate, weight_decay, batch_size):
train_ls, test_ls = [], []
train_iter = d2l.load_array((train_features, train_labels), batch_size)
# The Adam optimization algorithm is used here
trainer = gluon.Trainer(net.collect_params(), 'adam', {
'learning_rate': learning_rate, 'wd': weight_decay})
for epoch in range(num_epochs):
for X, y in train_iter:
with autograd.record():
l = loss(net(X), y)
l.backward()
trainer.step(batch_size)
train_ls.append(log_rmse(net, train_features, train_labels))
if test_labels is not None:
test_ls.append(log_rmse(net, test_features, test_labels))
return train_ls, test_ls
.. raw:: html
.. raw:: html
.. raw:: html
.. raw:: html
.. raw:: html
Kiểm định chéo gập k-lần
------------------------
.. raw:: html
Nếu bạn đang đọc cuốn sách này theo đúng thứ tự thì có thể bạn sẽ nhớ ra
rằng kiểm định chéo gập k-lần đã từng được giới thiệu khi ta thảo luận
về cách lựa chọn mô hình (: numref: ``sec_model_selection``). Ta sẽ ứng
dụng kỹ thuật này để lựa chọn thiết kế mô hình và điều chỉnh các siêu
tham số. Trước tiên ta cần một hàm trả về phần thứ :math:`i^\mathrm{th}`
của dữ liệu trong kiểm định chéo gập k-lần. Việc này được tiến hành bằng
cách cắt chọn (*slicing*) phần thứ :math:`i^\mathrm{th}` để làm dữ liệu
kiểm định và dùng phần còn lại làm dữ liệu huấn luyện. Cần lưu ý rằng
đây không phải là cách xử lý dữ liệu hiệu quả nhất và ta chắc chắn sẽ
dùng một cách khôn ngoan hơn để xử lý một tập dữ liệu có kích thước lớn
hơn nhiều. Nhưng sự phức tạp được thêm vào này có thể làm rối mã nguồn
một cách không cần thiết, vì vậy để đơn giản hóa vấn đề ở đây ta có thể
an toàn bỏ qua.
.. code:: python
def get_k_fold_data(k, i, X, y):
assert k > 1
fold_size = X.shape[0] // k
X_train, y_train = None, None
for j in range(k):
idx = slice(j * fold_size, (j + 1) * fold_size)
X_part, y_part = X[idx, :], y[idx]
if j == i:
X_valid, y_valid = X_part, y_part
elif X_train is None:
X_train, y_train = X_part, y_part
else:
X_train = np.concatenate((X_train, X_part), axis=0)
y_train = np.concatenate((y_train, y_part), axis=0)
return X_train, y_train, X_valid, y_valid
.. raw:: html
Trong kiểm định chéo gập k-lần, ta sẽ huấn luyện mô hình :math:`k` lần
và trả về trung bình lỗi huấn luyện và trung bình lỗi kiểm định.
.. code:: python
def k_fold(k, X_train, y_train, num_epochs,
learning_rate, weight_decay, batch_size):
train_l_sum, valid_l_sum = 0, 0
for i in range(k):
data = get_k_fold_data(k, i, X_train, y_train)
net = get_net()
train_ls, valid_ls = train(net, *data, num_epochs, learning_rate,
weight_decay, batch_size)
train_l_sum += train_ls[-1]
valid_l_sum += valid_ls[-1]
if i == 0:
d2l.plot(list(range(1, num_epochs+1)), [train_ls, valid_ls],
xlabel='epoch', ylabel='rmse',
legend=['train', 'valid'], yscale='log')
print('fold %d, train rmse: %f, valid rmse: %f' % (
i, train_ls[-1], valid_ls[-1]))
return train_l_sum / k, valid_l_sum / k
.. raw:: html
Lựa chọn Mô hình
----------------
.. raw:: html
Trong ví dụ này, chúng tôi chọn một bộ siêu tham số chưa được tinh chỉnh
và để dành việc cải thiện mô hình cho bạn đọc. Để tìm ra được một bộ
siêu tham số tốt có thể sẽ tốn khá nhiều thời gian tùy thuộc vào số
lượng siêu tham số mà ta muốn tối ưu. Nếu được sử dụng đúng cách, phương
pháp kiểm định chéo gập k-lần sẽ có tính ổn định cao khi thực hiện với
nhiều thử nghiệm. Tuy nhiên, nếu thử quá nhiều các lựa chọn siêu tham số
thì phương pháp này có thể thất bại vì ta có thể chỉ đơn thuần gặp may ở
một cách chia tập kiểm định phù hợp với bộ siêu tham số đó.
.. code:: python
k, num_epochs, lr, weight_decay, batch_size = 5, 100, 5, 0, 64
train_l, valid_l = k_fold(k, train_features, train_labels, num_epochs, lr,
weight_decay, batch_size)
print('%d-fold validation: avg train rmse: %f, avg valid rmse: %f'
% (k, train_l, valid_l))
.. parsed-literal::
:class: output
fold 0, train rmse: 0.169720, valid rmse: 0.157424
fold 1, train rmse: 0.162198, valid rmse: 0.189312
fold 2, train rmse: 0.163466, valid rmse: 0.167859
fold 3, train rmse: 0.167537, valid rmse: 0.154703
fold 4, train rmse: 0.162574, valid rmse: 0.182887
5-fold validation: avg train rmse: 0.165099, avg valid rmse: 0.170437
.. figure:: output_kaggle-house-price_vn_b10e5d_35_1.svg
.. raw:: html
Bạn sẽ thấy rằng đôi khi lỗi huấn luyện cho một bộ siêu tham số có thể
rất thấp, trong khi lỗi của kiểm định k-phần có thể cao hơn. Đây là dấu
hiệu của sự quá khớp. Vì vậy khi ta giảm lỗi huấn luyện, ta cũng nên
kiểm tra xem liệu lỗi kiểm định chéo gập k-lần có giảm tương ứng hay
không.
.. raw:: html
.. raw:: html
.. raw:: html
.. raw:: html
.. raw:: html
Dự đoán và Nộp bài
------------------
.. raw:: html
Bây giờ, khi đã biết được các lựa chọn tốt cho siêu tham số, ta có thể
sử dụng toàn bộ dữ liệu cho việc huấn luyện (thay vì chỉ dùng
:math:`1-1/k` của dữ liệu như trong quá trình kiểm định chéo). Sau đó,
ta áp dụng mô hình thu được lên tập kiểm tra và lưu các dự đoán vào một
tệp CSV nhằm đơn giản hóa quá trình tải kết quả lên Kaggle.
.. code:: python
def train_and_pred(train_features, test_feature, train_labels, test_data,
num_epochs, lr, weight_decay, batch_size):
net = get_net()
train_ls, _ = train(net, train_features, train_labels, None, None,
num_epochs, lr, weight_decay, batch_size)
d2l.plot(np.arange(1, num_epochs + 1), [train_ls], xlabel='epoch',
ylabel='rmse', yscale='log')
print('train rmse %f' % train_ls[-1])
# Apply the network to the test set
preds = net(test_features).asnumpy()
# Reformat it for export to Kaggle
test_data['SalePrice'] = pd.Series(preds.reshape(1, -1)[0])
submission = pd.concat([test_data['Id'], test_data['SalePrice']], axis=1)
submission.to_csv('submission.csv', index=False)
.. raw:: html
.. raw:: html
Ta nên kiểm tra xem liệu các dự đoán trên tập kiểm tra có tương đồng với
các dự đoán trong quá trình kiểm định chéo k-phần hay không. Nếu đúng là
như vậy thì đã đến lúc tải các dự đoán này lên Kaggle. Đoạn mã nguồn sau
sẽ tạo một tệp có tên ``submission.csv`` (CSV là một trong những định
dạng tệp được chấp nhận bởi Kaggle):
.. code:: python
train_and_pred(train_features, test_features, train_labels, test_data,
num_epochs, lr, weight_decay, batch_size)
.. parsed-literal::
:class: output
train rmse 0.162490
.. figure:: output_kaggle-house-price_vn_b10e5d_39_1.svg
.. raw:: html
Tiếp theo, như được mô tả trong hình :numref:`fig_kaggle_submit2`, ta
có thể nộp các dự đoán lên Kaggle và so sánh chúng với giá nhà thực tế
(các nhãn) trên tập kiểm tra. Các bước tiến hành khá là đơn giản:
.. raw:: html
- Đăng nhập vào trang web Kaggle và tìm đến trang của cuộc thi “House
Price Prediction”.
- Nhấn vào nút “Submit Predictions” hoặc “Late Submission” (nút này nằm
ở phía bên phải tại thời điểm viết sách).
- Nhấn vào nút “Upload Submission File” trong khung có viền nét đứt và
chọn tệp dự đoán bạn muốn tải lên.
- Nhấn vào nút “Make Submission” ở cuối trang để xem kết quả.
.. raw:: html
.. _fig_kaggle_submit2:
.. figure:: ../img/kaggle_submit2.png
:width: 400px
Tải dữ liệu lên Kaggle
.. raw:: html
.. raw:: html
.. raw:: html
Tóm tắt
-------
.. raw:: html
- Dữ liệu trong thực tế thường chứa nhiều kiểu dữ liệu khác nhau và cần
phải được tiền xử lý.
- Chuyển đổi dữ liệu có giá trị thực để có trung bình bằng không và
phương sai đơn vị là một phương án mặc định tốt. Tương tự với việc
thay thế các giá trị bị thiếu bằng giá trị trung bình.
- Chuyển đổi các biến hạng mục thành các biến chỉ định cho phép chúng
ta xử lý chúng như các vector.
- Ta có thể sử dụng kiểm định chéo gập k-phần để chọn ra mô hình và
điều chỉnh siêu tham số.
- Hàm Logarit có hữu ích đối với mất mát tương đối.
.. raw:: html
Bài tập
-------
.. raw:: html
1. Nộp kết quả dự đoán của bạn từ bài hướng dẫn này cho Kaggle. Các dự
đoán của bạn tốt đến đâu?
2. Bạn có thể cải thiện mô hình bằng cách giảm thiểu trực tiếp log giá
nhà không? Điều gì sẽ xảy ra nếu bạn dự đoán log giá nhà thay vì giá
thực?
3. Liệu việc thay thế các giá trị bị thiếu bằng trung bình của chúng
luôn luôn tốt? Gợi ý: bạn có thể dựng lên một tình huống khi mà các
giá trị không bị thiếu một cách ngẫu nhiên không?
4. Tìm cách biểu diễn tốt hơn để đối phó với các giá trị bị thiếu. Gợi
ý: điều gì sẽ xảy ra nếu bạn thêm vào một biến chỉ định?
5. Cải thiện điểm trên Kaggle bằng cách điều chỉnh các siêu tham số
thông qua kiểm định chéo gập k-lần.
6. Cải thiện điểm bằng cách cải thiện mô hình (các tầng, điều chuẩn,
dropout).
7. Điều gì sẽ xảy ra nếu ta không chuẩn hóa đặc trưng số liên tục như ta
đã làm trong phần này?
.. raw:: html
.. raw:: html
.. raw:: html
Thảo luận
---------
- `Tiếng Anh `__
- `Tiếng Việt `__
Những người thực hiện
---------------------
Bản dịch trong trang này được thực hiện bởi:
- Đoàn Võ Duy Thanh
- Nguyễn Lê Quang Nhật
- Phạm Minh Đức
- Lê Khắc Hồng Phúc
- Phạm Hồng Vinh
- Nguyễn Duy Du
- Trần Yến Thy
- Vũ Hữu Tiệp