在本教程中,您将:
1. 创建笔记本实例
2. 准备数据
3. 训练模型以从数据中学习
4. 部署模型
5. 评估您的机器学习模型的性能
管理亚马逊云科技资源
登录控制台导航到 Amazon SageMaker 控制台。
1. 单击此处之后,亚马逊云科技管理控制台将在新窗口中打开,因此您可以使本分步指南保持打开状态。开始在搜索栏中键入 SageMaker,并选择 Amazon SageMaker 以打开服务控制台。
4. 完成新建后就可以在notebook里开展我们后续的⼀系列⼯作了,⾸先我们安装基本的库:
!pip install sagemaker pandas
5. 之后,我们import⼀些基本的module,并把S3的数据加载到当前⽬录,做⼀个简单的数据探索:
import time import boto3 import sagemaker import urllib import pandas as pd from sklearn.model_selection import train_test_split # 获取当前AWS region和notebook所绑定的role role = sagemaker.get_execution_role() region = boto3.Session().region_name # 设置数据存放的桶和工作目录 bucket = 'sagemaker-bucket-xgb' prefix = 'ori-data' # 可以使用 SageMaker session 来上传下载数据,这里把S3的训练数据下载到当前目录 sm_session = sagemaker.Session() sm_session.download_data("./", bucket, prefix + 'train.csv') sm_session.download_data("./", bucket, prefix + 'test.csv') # 通过describe来对查看一下训练数据feature的构成和分布 X_full=pd.read_csv("./train.csv", index_col='Id') X_full.describe()
describe的结果如图所示,我们可以看到训练数据有很多字段构成,同时可以看到每个字段的取值分布情况,⽐如LotArea这个字段我们可以看到取值范围从1300到215245,平均值10516.828082,以及25%,50%,75%的分位数(Quantile)取值,也可以借助一些matplotlib,seaborn等图形化的库来更好做这种数据探索,好的数据探索对我们后续做数据预处理、改善模型的准确度都是很有帮助的。
从上⾯的describe结果来看,⾥⾯⼀些feature的取值有⼀些不寻常的特点,对于当前的数据我们做⼀个简单的预处理:丢弃没有SalePrice的sample:
除了丢弃没有SalePrice的sample以外,我们还做了另外⼀个处理”提取训练数据中的label列,在原始数据中丢弃label列“,这是因为SageMaker的内置XGBoost算法对于输⼊数据有两个要求:
1. 训练数据要是把label作为⾸列,我们这⾥先把label从原始数据提取了出来,后⾯还会再把它作为第⼀列拼接回训练数据中;
2. 训练数据⾥不能有表头信息(就是诸如MSSubClass,LotFrontage这些列名)
另外,为了后⾯模型训练过程中验证模型的合理性我们还要对原始训练数据做⼀个拆分。把原始的训练数据拆分成training set和validation set。sklearn提供了很多⽤来做数据拆分的⼯具,我们这⾥直接调⽤它的⼀个函数来实现这个拆分:
# 丢弃没有SalePrice的sample X = pd.read_csv("./train.csv", index_col='Id') X.dropna(axis=0, subset=['SalePrice'], inplace=True) # 提取训练数据中的label列,在原始数据中丢弃label列 y = X.SalePrice X.drop(['SalePrice'], axis=1, inplace=True) # 拆分原始训练数据为四份,X_train_full, X_valid_full, y_train, y_valid X_train_full, X_valid_full, y_train, y_valid = train_test_split(X, y, train_size=0.8, test_size=0.2, random_state=0)
7. 特征⼯程的引⼊是为了让我们的算法更好的理解特征⽽引⼊的。这里我们采⽤one-hot encoding来对可枚举的属性编码时,如果属性的取值个数过多,会导致产⽣过多的数据,在这⾥我们选择只对取值个数少于10的属性来做one-hot encoding,具体如下:
# Cardinality 代表的就是某个枚举类型的属性取值范围个数 # 这里是要筛选出 Cardinality 小于10的属性 low_cardinality_cols = [cname for cname in X_train_full.columns if X_train_full[cname].nunique() < 10 and X_train_full[cname].dtype == "object"] # 筛选出数字类型的列 numeric_cols = [cname for cname in X_train_full.columns if X_train_full[cname].dtype in ['int64', 'float64']] # 把Cardinality小于10和数字类型的列拼在一起作为全部的列 my_cols = low_cardinality_cols + numeric_cols # 在training set 和 validation set 中只保留通过上面方法筛选出来的列 X_train = X_train_full[my_cols].copy() X_valid = X_valid_full[my_cols].copy() # 做 one-hot encoding X_train = pd.get_dummies(X_train) X_valid = pd.get_dummies(X_valid) X_train, X_valid = X_train.align(X_valid, join='left', axis=1)
在此步骤中,您将使用训练数据集训练您的机器学习模型。
1. 要使用 Amazon SageMaker 预构建的 XGBoost 模型,您需要重新格式化训练数据的标题和第一列,并将结果存储在S3上。将以下代码复制到新的代码单元格中,然后选择运行
# 对于training set 把label数据挪到第一列,去掉表头保存到当前目录 X_train_xgb= pd.concat([y_train,X_train], axis=1) X_train_xgb.to_csv('./X_train.csv',header=False,index=False) # 对于validation set 同样的把label数据挪到第一列,去掉表头保存到当前目录 X_valid_xgb= pd.concat([y_valid,X_valid], axis=1) X_valid_xgb.to_csv('./X_valid.csv',header=False,index=False) # 把准备的数据输入放到S3的工作目录里 train_data_location = 's3://{}/{}/{}'.format(bucket, prefix, 'train') validation_data_location = 's3://{}/{}/{}'.format(bucket, prefix, 'validation') sm_session.upload_data('./X_train.csv',bucket,prefix) sm_session.upload_data('./X_valid.csv',bucket,prefix)
2. 接下来,您需要设置 Amazon SageMaker 会话,创建 XGBoost 模型(估算器)的实例,并定义模型的超参数。将以下代码复制到新的代码单元格中,然后选择运行,几分钟后,您应开始看到正在生成的训练日志。
# 我们使⽤SageMaker内置的XGBoost来训练,⾸先要获取这个算法的container from sagemaker.amazon.amazon_estimator import get_image_uri container = get_image_uri(region, 'xgboost', repo_version='0.90-2') # 设置算法超参 hyperparameters = { "max_depth":"5", "eta":"0.5", "early_stopping_rounds":"5", "eval_metric":"mae", "num_round":"20"} # 训练使⽤哪种EC2实例来完成 instance_type = 'ml.m5.2xlarge' # 模型输出⽬录 output_path = 's3://{}/{}/output'.format(bucket, prefix) # 训练输⼊数据的类型 content_type = "csv" # 设置训练任务的名字 job_name = 'xgb-housing-' + time.strftime("%Y-%m-%d-%H-%M-%S", time.gmtime()) print("Training job", job_name) # 借助 Managed Spot Training 功能,⼤幅降低训练成本 train_use_spot_instances = True train_max_run = 3600 train_max_wait = 7200 if train_use_spot_instances else None checkpoint_s3_uri = ('s3://{}/{}/checkpoints/{}'.format(bucket, prefix, job_name) if train_use_spot_instances else None) # 在SageMaker⾥的使⽤任何算法来训练都要先⽣成⼀个 estimator 对象 estimator = sagemaker.estimator.Estimator(container, role, hyperparameters=hyperparameters, train_instance_count=1, train_instance_type=instance_type, train_volume_size=5, # 5 GB output_path=output_path, sagemaker_session=sagemaker.Session(), train_use_spot_instances=train_use_spot_instances, train_max_run=train_max_run, train_max_wait=train_max_wait, checkpoint_s3_uri=checkpoint_s3_uri ); # 设置训练数据的 data channel train_data_location = 's3://{}/{}/{}'.format(bucket, prefix, 'X_train.csv') validation_data_location = 's3://{}/{}/{}'.format(bucket, prefix, 'X_valid.csv') train_channel = sagemaker.session.s3_input(train_data_location, content_type='text/csv') valid_channel = sagemaker.session.s3_input(validation_data_location, content_type='text/csv') data_channels = {'train': train_channel, 'validation': valid_channel} # 调⽤ fit 来训练 estimator.fit(inputs=data_channels, job_name=job_name, logs=True)
4. tuning job内部需要先有⼀个training job,然后通过不断优化超参,来使得training job的评估指标最优。这⼀步就是创建这个training job,设置名字叫 xgb-housing-training-job 的训练job,然后在后续的界⾯中按照图示设置如何⾃动调参。
objective metric就是评估指标,我们这⾥还是选择mae。在Hyperparameter configuration这⾥,SageMaker会⾃动的把XGBoost相关的超参列出来供我们进⾏调整。IAM role就选择之前创建notebook时创建的role即可。
现在我们要使⽤上图中的部署好的endpoint来做推理。跟上⾯在训练的时候提到的 Estimator 类似,SageMaker Python SDK也对推理调⽤有统⼀的抽象,这个名字是Predictors,任何的推理调⽤都要⾸先创建⼀个RealTimePredictor,然后调⽤它的predict⽅法,如下:
from sagemaker.predictor import csv_serializer # 创建 predictor xgb_predictor=sagemaker.predictor.RealTimePredictor( "xgb-housing", // 这个名字就是上图中蓝⾊⽅框中endpoint的name sagemaker_session=sm_session, serializer=csv_serializer, content_type='text/csv') # 调⽤predictor的predict⽅法做推理 xgb_predictor.predict(X_valid.values[0]).decode('utf-8')