1.下载缓存数据集
字典DATA_HUB,二元组包含数据集的url和验证文件完整性的sha-1密钥
import hashlibimport osimport tarfileimport zipfileimport requests#@saveDATA_HUB = dict()DATA_URL = 'http://d2l-data.s3-/'
download到本地目录(默认情况下为…/data)并返回下载文件的名称
def download(name, cache_dir=os.path.join('..', 'data')): #@save"""下载一个DATA_HUB中的文件,返回本地文件名。"""assert name in DATA_HUB, f"{name} 不存在于 {DATA_HUB}."url, sha1_hash = DATA_HUB[name]os.makedirs(cache_dir, exist_ok=True)fname = os.path.join(cache_dir, url.split('/')[-1])if os.path.exists(fname):sha1 = hashlib.sha1()with open(fname, 'rb') as f:while True:data = f.read(1048576)if not data:breaksha1.update(data)if sha1.hexdigest() == sha1_hash:return fname # Hit cacheprint(f'正在从{url}下载{fname}...')r = requests.get(url, stream=True, verify=True)with open(fname, 'wb') as f:f.write(r.content)return fname
2.访问和读取数据集
# 如果pandas没有被安装,请取消下一句的注释。# !pip install pandas%matplotlib inlineimport numpy as npimport pandas as pdimport torchfrom torch import nnfrom d2l import torch as d2lDATA_HUB['kaggle_house_train'] = ( #@saveDATA_URL + 'kaggle_house_pred_train.csv','585e9cc93e70b39160e7921475f9bcd7d31219ce')DATA_HUB['kaggle_house_test'] = ( #@saveDATA_URL + 'kaggle_house_pred_test.csv','fa19780a7b011d9b009e8bff8e99922a8ee2eb90')
train_data = pd.read_csv(download('kaggle_house_train'))test_data = pd.read_csv(download('kaggle_house_test'))print(train_data.shape)print(test_data.shape)print(train_data.iloc[0:4, [0, 1, 2, 3, -3, -2, -1]])
all_features = pd.concat((train_data.iloc[:, 1:-1], test_data.iloc[:, 1:]))
2.数据预处理
使特征具有零均值和单位方差,即 E[x−μσ]=μ−μσ=0 和 E[(x−μ)2]=(σ2+μ2)−2μ2+μ2=σ2 。
numeric_features = all_features.dtypes[all_features.dtypes != 'object'].indexall_features[numeric_features] = all_features[numeric_features].apply(lambda x: (x - x.mean()) / (x.std()))# 在标准化数据之后,所有数据都意味着消失,因此我们可以将缺失值设置为0all_features[numeric_features] = all_features[numeric_features].fillna(0)
one-hot编码
# `Dummy_na=True` 将“na”(缺失值)视为有效的特征值,并为其创建指示符特征。all_features = pd.get_dummies(all_features, dummy_na=True)all_features.shape
从pandas的numpy格式转成tensor格式
n_train = train_data.shape[0]train_features = torch.tensor(all_features[:n_train].values,dtype=torch.float32)test_features = torch.tensor(all_features[n_train:].values,dtype=torch.float32)train_labels = torch.tensor(train_data.SalePrice.values.reshape(-1, 1),dtype=torch.float32)
3.训练
loss = nn.MSELoss()in_features = train_features.shape[1]def get_net():net = nn.Sequential(nn.Linear(in_features, 1))return net
def log_rmse(net, features, labels):# 为了在取对数时进一步稳定该值,将小于1的值设置为1clipped_preds = torch.clamp(net(features), 1, float('inf'))rmse = torch.sqrt(loss(torch.log(clipped_preds), torch.log(labels)))return rmse.item()
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)# 这里使用的是Adam优化算法optimizer = torch.optim.Adam(net.parameters(), lr=learning_rate,weight_decay=weight_decay)for epoch in range(num_epochs):for X, y in train_iter:optimizer.zero_grad()l = loss(net(X), y)l.backward()optimizer.step()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
4.k折交叉验证
将数据划分
def get_k_fold_data(k, i, X, y):assert k > 1fold_size = X.shape[0] // kX_train, y_train = None, Nonefor 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_partelif X_train is None:X_train, y_train = X_part, y_partelse:X_train = torch.cat([X_train, X_part], 0)y_train = torch.cat([y_train, y_part], 0)return X_train, y_train, X_valid, y_valid
def k_fold(k, X_train, y_train, num_epochs, learning_rate, weight_decay,batch_size):train_l_sum, valid_l_sum = 0, 0for 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', xlim=[1, num_epochs],legend=['train', 'valid'], yscale='log')print(f'fold {i + 1}, train log rmse {float(train_ls[-1]):f}, 'f'valid log rmse {float(valid_ls[-1]):f}')return train_l_sum / k, valid_l_sum / k
5.模型选择
k, num_epochs, lr, weight_decay, batch_size = 5, 100, 5, 0, 64train_l, valid_l = k_fold(k, train_features, train_labels, num_epochs, lr,weight_decay, batch_size)print(f'{k}-折验证: 平均训练log rmse: {float(train_l):f}, 'f'平均验证log rmse: {float(valid_l):f}')
6.提交到kaggle
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='log rmse', xlim=[1, num_epochs], yscale='log')print(f'train log rmse {float(train_ls[-1]):f}')# 将网络应用于测试集。preds = net(test_features).detach().numpy()# 将其重新格式化以导出到Kaggletest_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)
train_and_pred(train_features, test_features, train_labels, test_data,num_epochs, lr, weight_decay, batch_size)
提交到kaggle(以下两步建议科学上网)
1.注册账号
2.Make Submission
总结
图像识别中,减均值除方差没什么用,在输入层加个BN就可以了
特征维度多或者少,影响不大
疑问:
k折交叉验证,可以尽可能的在数据量不大的前提下,使用更多的数据量进行训练,但是这样的话,会有不同的模型,模型选择问题
答:K折交叉验证只要是看模型的泛化能力的,另外也有使用更多的数据量进行训练的意思。
怎么kaggle上传自己的模型呢,
答:net实例中就包含了权重参数。