主要内容记录对于机器学习超参数调整原理,部署相关记录
常用的超参数框架有很多:
- Hyperopt
- Scikit Optimize
- Optuna
- NNI
这里主要使用NNI进行部署(简单便捷,支持一键多卡、log输出)
超参数优化
1.优化框架Microsoft NNI
操作文档:NNI Documentation — Neural Network Intelligence
========注意:本文档记录于NNI2.0时期,现在已更新至3.0,可能会有所不同=======
1.1 使用教程
1.使用argparser
包引入相关超参数
2.将相关参数按照新格式引入原模型
3.期间评价参数使用nni.report_intermediate_result(val_loss)
time_dif = get_time_dif(start_time)
val_loss = evaluate(model, config, val_loader) # 这是你的模型评价参数
'''
nni修改之处,中间评估参数【加入下列代码,让nni获取你的模型评价值】
'''
nni.report_intermediate_result(val_loss)
4.总体评价参数使用nni.report_final_result(val_loss)
nni.report_final_result(val_loss)
# 当你的模型所有的epoch跑完,输出训练后选择的最佳模型评价指标
5.参数引入与更新nni.get_next_parameter()
这里使用tune_params输入到模型中进行迭代计算
if __name__ == '__main__':
try:
tuner_params = nni.get_next_parameter()
print(tuner_params)
params = vars(get_param()) # namespace->dict
params.update(tuner_params)
main(params)
except Exception as exception:
print(exception)
6.运行nni
一种方式是通过py文件进行运行:下面是代码示例
from nni.experiment import Experiment
search_space = {
"num_layers": {"_type": "choice", "_value": [1, 2, 3, 4, 5]},
"hidden_size": {"_type": "choice", "_value": [64, 128, 256, 512, 1024]},
"lr": {"_type": "choice", "_value": [0.0001, 0.001, 0.01, 0.1]},
"dropout_rate": {"_type": "uniform", "_value": [0, 1]}
}
experiment = Experiment('local')
experiment.config.experiment_name = 'test_experiment'
experiment.config.trial_command = 'python 0411_NNI_Data.py'
experiment.config.trial_code_directory = '.'
experiment.config.search_space = search_space
experiment.config.tuner.name = 'TPE'
experiment.config.tuner.class_args['optimize_mode'] = 'maximize'
experiment.config.max_trial_number = 10
experiment.config.trial_concurrency = 1
experiment.run(8088)
# input('Press enter to quit')
# experiment.stop()
seach_space即超参数的取值范围:可以定义类型“choice”、“uniform”等离散或者连续的变量,包含数值、字符等变量。
另一种是通过config.yml
文件命令行直接运行,同时可以将search_space
文件单独列为.json
文件
运行命令:nnictl create --config your_file_name/config.yml --port 8088
# This is the minimal config file for an NNI experiment.
# Use "nnictl create --config config.yml" to launch this experiment.
# Afterwards, you can check "config_detailed.yml" for more explanation.
# 运行:nnictl create --config your_file_name/config.yml --port 8088
experimentName: LSTM
searchSpaceFile: search_space.json
trialCommand: python 0411_NNI_Data.py
trialCodeDirectory: .
trialGpuNumber: 1
trialConcurrency: 1
maxExperimentDuration: 2h
maxTrialNumber: 10
tuner:
name: TPE
classArgs:
optimize_mode: maximize
trainingService:
platform: local
useActiveGpu: True
1.2 nni常用指令
# 运行
nnictl create --config your_file_name/config.yml --port 8088
nnictl create [-h] --config CONFIG [--port PORT] [--debug]
[--url_prefix URL_PREFIX] [--foreground]
# 查看
nnictl view --port 8088 a0fevbwc
# 这里的a0fevbwc就是你的nni实例的id
nnictl view [-h] [--port PORT] [--experiment_dir EXPERIMENT_DIR] id
# 复原
nnictl resume [-h] [--port PORT] [--debug] [--foreground]
[--experiment_dir EXPERIMENT_DIR]
id
The Web UI urls are: http://223.255.255.1:8080 http://127.0.0.1:8080 ----------------------------------------------------------------------- You can use these commands to get more information about the experiment ----------------------------------------------------------------------- commands description 1. nnictl experiment show show the information of experiments 2. nnictl trial ls list all of trial jobs 3. nnictl top monitor the status of running experiments 4. nnictl log stderr show stderr log content 5. nnictl log stdout show stdout log content 6. nnictl stop stop an experiment 7. nnictl trial kill kill a trial job by id 8. nnictl --help get help information about nnictl -----------------------------------------------------------------------
1.3 使用过程中碰到的问题以及解决方案
1.防止结束后退出
如果您使用的是普通 Python 而不是 Jupyter Notebook, 您可以在代码末尾加上一行 input()
或者 signal.pause()
来避免 Python 解释器自动退出, 这样您就能继续使用网页控制台。
实验完全停止之后,您可以使用 nni.experiment.Experiment.view() 重新启动网页控制台。
2. 错误:experimentconfig: type of experiment_name (none) is not typing.union[str, nonetype]
以及AttributeError: 'dict' object has no attribute 'name'
NNI v2.x users may need to manually downgrade typeguard by pip install "typeguard<3"
This will be fixed in upcoming v3.0 release【现在已经更新至3.0】
参考链接:incompatible with new typeguard version · Issue #5452 · microsoft/nni · GitHub
3. 问题:有时候用GPU跑?logging参数设置
有时候运行时间过长,某个trial会陷入dead状态,进程不动,在无人值守状态下极易造成时间资源浪费,目前原因不知。
4. 使用技巧--记得设置每个trail的限制时长
设置之后可以规避问题三。
5. 脚本提取超参数数据,中间过程数据等--科研作图用
nni输出的log里包含所有的中间参数信息,包括超参数调整的过程中每个trail的超参数、结果、中间进程的结果等。但论文、报告撰写过程一般需要各位按照要求画图,nni的log目录结构是按照一个nni项目大id目录下多个trial的小id进行分布,故这里使用爬虫过滤一下log内容。
这里给出提取超参数的爬虫代码示例:
import re
import csv
def extract_parameters(file_path):
parameters = []
with open(file_path, 'r', encoding='utf-8') as file:
data = file.read()
# 这里pattern为你所需要内容的正则表达式
pattern = r'"parameters":\s\{"num_layers":\s\d+,\s"hidden_size":\s\d+,\s"window_size":\s\d+,\s"batch_size":\s\d+,\s"lr":\s\d+\.\d+,\s"input_size":\s\d+,\s"dropout_rate":\s\d+\.\d+\},'
matches = re.findall(pattern, data, re.DOTALL)
# 解析为Python数据结构
csv_data = []
dr=0.
for match in matches:
match = match.strip(',') # 去除末尾的逗号
match = match.replace('"parameters": ', '') # 去除"parameters":
eval_data = eval(match) # 将字符串解析为Python字典
if (dr != eval_data["dropout_rate"]):
dr = eval_data["dropout_rate"]
csv_data.append(eval_data) # 提取字典中的values作为CSV的一行
# 写入CSV文件
column_names = list(csv_data[0].keys())
csv_file_path = "D:\\Data\\NNIlog\\nni_parameters.csv"
with open(csv_file_path, mode='w', newline='') as file:
writer = csv.DictWriter(file, fieldnames=column_names)
# 写入CSV文件头部
writer.writeheader()
# 写入数据行
writer.writerows(csv_data)
print(f"CSV文件已保存至:{csv_file_path}")
file_path = 'D:\\Data\\NNIlog\\nnimanager.txt' # 你的目录
parameters_list = extract_parameters(file_path)
print(parameters_list)
1.4 需要回顾的问题
1.NNI版本大更新
2.更新后的数据收集需要重写爬虫代码
2.超参数优化原理
2.1 总体超参数优化一览
这里主要参考论文:
《algorithms-for-hyper-parameter-optimization》
《On hyperparameter optimization of machine learning algorithms——Theory and practice》
下图为常用的超参数优化算法的优缺点。
下图为机器学习模型适用的超参数优化算法总结