深度学习或机器学习过程中少不了需要对训练过程进行额外处理,比如我们想观察score的变化,相关差准确率变化的趋势。
除了用模型自带的plot工具,我们也需要自己进行集中处理或对中间过程进行缓存。
原始输入:
{'Role': 'Server #', 'Round': 1, 'Results_raw': {'test_f1': 0.10770681986233807, 'test_total': 609, 'test_avg_loss': 1.9486457109451294, 'test_loss': 1186.7252379655838, 'val_f1': 0.08549080600237736, 'val_total': 542, 'val_avg_loss': 1.949989914894104, 'val_loss': 1056.8945338726044}}
{'Role': 'Server #', 'Round': 2, 'Results_raw': {'test_f1': 0.11019650206846494, 'test_total': 609, 'test_avg_loss': 1.9490487575531006, 'test_loss': 1186.9706933498383, 'val_f1': 0.09533932757526807, 'val_total': 542, 'val_avg_loss': 1.9504367113113403, 'val_loss': 1057.1366975307465}}
{'Role': 'Server #', 'Round': 3, 'Results_raw': {'test_f1': 0.11728175062534404, 'test_total': 609, 'test_avg_loss': 1.9500796794891357, 'test_loss': 1187.5985248088837, 'val_f1': 0.09500389029711606, 'val_total': 542, 'val_avg_loss': 1.9511232376098633, 'val_loss': 1057.508794784546}}
{'Role': 'Server #', 'Round': 4, 'Results_raw': {'test_f1': 0.11653842664371827, 'test_total': 609, 'test_avg_loss': 1.9523628950119019, 'test_loss': 1188.9890030622482, 'val_f1': 0.10123642955228289, 'val_total': 542, 'val_avg_loss': 1.9534810781478882, 'val_loss': 1058.7867443561554}}
{'Role': 'Server #', 'Round': 5, 'Results_raw': {'test_f1': 0.12422168569025195, 'test_total': 609, 'test_avg_loss': 1.9476524591445923, 'test_loss': 1186.1203476190567, 'val_f1': 0.10875485804792952, 'val_total': 542, 'val_avg_loss': 1.948114037513733, 'val_loss': 1055.8778083324432}}
{'Role': 'Server #', 'Round': 6, 'Results_raw': {'test_f1': 0.12414008225265606, 'test_total': 609, 'test_avg_loss': 1.9449809789657593, 'test_loss': 1184.4934161901474, 'val_f1': 0.11250335618480363, 'val_total': 542, 'val_avg_loss': 1.9455983638763428, 'val_loss': 1054.5143132209778}}
{'Role': 'Server #', 'Round': 7, 'Results_raw': {'test_f1': 0.12411816681585039, 'test_total': 609, 'test_avg_loss': 1.9439574480056763, 'test_loss': 1183.8700858354568, 'val_f1': 0.11951172297016435, 'val_total': 542, 'val_avg_loss': 1.9443539381027222, 'val_loss': 1053.8398344516754}}
{'Role': 'Server #', 'Round': 8, 'Results_raw': {'test_f1': 0.12847046900504241, 'test_total': 609, 'test_avg_loss': 1.9428367614746094, 'test_loss': 1183.187587738037, 'val_f1': 0.12268099263223001, 'val_total': 542, 'val_avg_loss': 1.9436607360839844, 'val_loss': 1053.4641189575195}}
{'Role': 'Server #', 'Round': 9, 'Results_raw': {'test_f1': 0.12793590888828985, 'test_total': 609, 'test_avg_loss': 1.9407541751861572, 'test_loss': 1181.9192926883698, 'val_f1': 0.12519074687255302, 'val_total': 542, 'val_avg_loss': 1.941501259803772, 'val_loss': 1052.2936828136444}}
...
{'Role': 'Server #', 'Round': 200, 'Results_raw': {'test_f1': 0.5866941248560479, 'test_total': 609, 'test_avg_loss': 1.7052942514419556, 'test_loss': 1038.524199128151, 'val_f1': 0.5982337308802026, 'val_total': 542, 'val_avg_loss': 1.7150903940200806, 'val_loss': 929.5789935588837}}
{'Role': 'Server #', 'Round': 'Final', 'Results_raw': {'server_global_eval': {'val_loss': 929.5789935588837, 'test_f1': 0.5866941248560479, 'test_total': 609, 'test_avg_loss': 1.7052942514419556, 'test_loss': 1038.524199128151, 'val_f1': 0.5982337308802026, 'val_total': 542, 'val_avg_loss': 1.7150903940200806}}}
我们的提取目标是,获取每一次迭代中的'test_f1'对应的数值。
初步分析可以值,文件中每一round数据结果是按行进行存储。格式是几乎统一的。
所以我们可以将文件用Python按行读取,进行处理,并且将数据处理之后存入一个列表当中。
那剩下的工作就是如何对每行数据进行处理了。
首先给出整体代码:
import ast, json
def fetch_data(file_name):
f = open(file_name, "r")
print("begin to fetch the data.")
# 总信息字典的列表
data = []
# 感兴趣的字典的列表
special_data = []
special_data_array = []
line = f.readline()
last_round = 0
while line:
# 因为其他行数和末行的格式有点不同,需要特判
# print(line)
row_dict = ast.literal_eval(line)
# 当前训练回合数
round = 0
# 目标值
test_f1 = 0
if row_dict['Round'] != "Final":
round = int(row_dict['Round'])
last_round = round
test_f1 = float(row_dict['Results_raw']['test_f1'])
else:
# 最后一行,只是汇总,不代表训练了第last_round+1次
round = last_round + 1
test_f1 = float(row_dict['Results_raw']['server_global_eval']['test_f1'])
# 可以根据自己的需要提取
special_data.append({round:test_f1})
special_data_array.append(test_f1)
data.append(row_dict)
# 读取下一行数据
line = f.readline()
f.close()
# 打印便于观察
# print(special_data)
# 以自己需要的格式输出
jsonStr = json.dumps(special_data)
jsonFile = open("output_data.json", "w")
jsonFile.write(jsonStr)
jsonFile.close()
if __name__=="__main__":
fetch_data("eval_results.log")
读取每一行样本:
line = f.readline()
此时line为str格式,注意不能直接调用json.loads()函数,可以观察我们提供的内容中,期待作为key的部分是单引号''包括的,如果不能调整模型输出,我们就不能直接调用json.loads().这样会报错:Expecting property name enclosed in double quotes: line 1 column 2 (char 1)
注意:字符串中,双引号在外围,单引号在内嵌,导致转换失败,可以使用json5
进行处理
但是为了方便提取,我们仍然需要对这一行str,且可以得到JSON格式的内容进行处理,这里可以用到。
str to JSON
使用literal_eval
import ast
str1 = "{'a': 1, 'b': 2}"
json1 = ast.literal_eval(str1)
print(type(json1))
print(json1)
# 输出
<class 'dict'>
{'a': 1, 'b': 2}
使用eval
val的作用:将字符串str当成有效的表达式来求值并返回计算结果。即可以通过eval
可以把list
、tuple
、dict
和string
相互转化。
使用json.loads()
字符串str转json对象,需要使用json模块的loads函数,注意样本特征。
import json
str1 = '{"accessToken": "521de21161b23988173e6f7f48f9ee96e28", "User-Agent": "Apache-HttpClient/4.5.2 (Java/1.8.0_131)"}'
json1 = json.loads(str1)
print(json1)
print(type(json1))
# 输出
{'accessToken': '521de21161b23988173e6f7f48f9ee96e28', 'User-Agent': 'Apache-HttpClient/4.5.2 (Java/1.8.0_131)'}
<class 'dict'>
获取到我们需要的dict之后,就可以层层根据key获取值了。
如果要输出,我们用json.dumps()处理数据,得到我们需要的文本格式,然后用file模块的write进行输出即可。这部分比较灵活。
比如最理想的输出格式,我们想得到带有缩进的JSON,方便观察,可以添加indent字段,并配合sort_keys让输出内容根据key值进行字典序排列。
import json
print(json.dumps({'4': 5, '6': 7}, sort_keys=True, indent=4))
{
"4": 5,
"6": 7
}
最终输出结果呈现如下:
[
{
"1": 0.10770681986233807
},
{
"2": 0.11019650206846494
},
{
"3": 0.11728175062534404
},
...
{
"199": 0.5853299926818857
},
{
"200": 0.5866941248560479
},
{
"201": 0.5866941248560479
}
]
任务达成。
参考资料:
【python】str与json类型转换_str转json_sysu_lluozh的博客-CSDN博客
json — JSON encoder and decoder — Python 3.11.3 documentation