Tf.keras.Model class ~ 自变量性能
Tf.keras.Model class ~ self variables performance
已编辑:
事实证明,基础 class 在继承 Tf.keras.Model
的继承树中更高,当此 class 继承存在时,可以观察到下面描述的行为。与普通脚本相比,普通 Python class 的性能可以忽略不计。
我还没有找到任何与此行为相关的文档,如果有可用的更新将随之而来。
编辑 2:
我没有找到任何关于此的文档(因此需要确认),但似乎是:
如果我将任何对象分配给 self
(在继承 class 的 Tf.keras.Model
中),所有包含的 tf.Variables
都将被提取并出现在 trainable_variables
的 [=] 属性中79=]。所以我的假设是 keras.Model
检查对 self
的任何分配,试图找到一些特定的对象,而这种检查导致 self
对一个巨大的 dict 的分配很慢。
供参考:检查深入嵌套列表和字典,但不检查 classes 除非它们扩展 ts.keras.Model
或 tf.keras.Layer
原问题:
我有一个字符串列表 col
(约 30 万行,约 30 个字符的字符串给你一个想法)。准确地说是 pandas.DataGrid
而不是列表。
我正在创建一个查找字典以供将来使用,如下所示:
direct = {}
inverse = {}
# progressive
progressive = 0
# create direct map
for label in col:
# skip if present
if str(label) in direct:
continue
# else add to direct
direct[str(label)] = progressive
inverse[progressive] = str(label)
progressive += 1
这里没有什么奇怪的,它需要 0.15 秒并且 python 进程内存使用是合理的。
然后我将我的代码移到 class 中,这里事情变得奇怪了。这里提供了同一功能的两个略有不同的版本。
版本 A:
def fromDataset(self, column):
# reset map
self.direct = {}
self.inverse = {}
# progressive
progressive = 0
# create direct map
for label in column:
# skip if present
if str(label) in self.direct:
continue
# else add to direct
self.direct[str(label)] = progressive
self.inverse[progressive] = str(label)
progressive += 1
版本 B:
def fromDataset(self, column):
# reset map
direct = {}
inverse = {}
# progressive
progressive = 0
# create direct map
for label in column:
# skip if present
if str(label) in direct:
continue
# else add to direct
direct[str(label)] = progressive
inverse[progressive] = str(label)
progressive += 1
self.direct = direct
self.inverse = inverse
所有建议的函数产生相同的结果(约 120k 个条目的字典,占用约 30MB RAM)
我可以接受版本 A 可能会比版本 B 慢访问 self
变量,但我无法理解的是版本 B 怎么可能花费 2.16 秒(比以前多 14 倍)天气版本 A 甚至无法测试(10 多分钟后还没有结果,进程内存使用量增加了 500+ MB)
更奇怪的是,版本 B 需要 0.17 秒来创建字典,~2 秒来执行:
self.direct = direct
self.inverse = inverse
在为此迷失了整整一天之后,我开始怀疑是否缺少与 Python 内存分配相关的内容。我得出的唯一有意义的假设是 self.direct = direct
导致 Python 实际上 move/copy ram 中的字典。
任何人都可以解释一下版本 A 和版本 B 中发生了什么,这与直接脚本版本有如此根本的不同吗?
我创建了一个可重现的示例并且没有遇到任何问题:
import random
import string
import pandas
def gen_random_word(word_length=30):
return ''.join((random.choice(string.ascii_letters) for _ in range(word_length)))
# I create a list of 300000 labels (but only 150k distinct labels) of 30 characters
labels = [gen_random_word() for _ in range(150000)]
labels = labels + labels
random.shuffle(labels)
# A dataframe here is useless but I try to get close to your own example
df = pandas.DataFrame(
{'labels': labels}
)
class A:
def __init__(self):
self.direct = {}
self.inverse = {}
self.progressive = 0
def fromDataset(self, column):
# create direct map
for label in column:
# skip if present
if str(label) in self.direct:
continue
# else add to direct
self.direct[str(label)] = self.progressive
self.inverse[self.progressive] = str(label)
self.progressive += 1
class B:
def __init__(self):
self.direct = {}
self.inverse = {}
self.progressive = 0
def fromDataset(self, column):
# reset map
direct = {}
inverse = {}
# progressive
progressive = 0
# create direct map
for label in column:
# skip if present
if str(label) in direct:
continue
# else add to direct
direct[str(label)] = progressive
inverse[progressive] = str(label)
progressive += 1
self.direct = direct
self.inverse = inverse
self.progressive = progressive
第一次测试:
%%time # remove that if you are not using jupyter and use another timing solution
direct = {}
inverse = {}
# progressive
progressive = 0
# create direct map
for label in df['labels']:
# skip if present
if str(label) in direct:
continue
# else add to direct
direct[str(label)] = progressive
inverse[progressive] = str(label)
progressive += 1
挂墙时间:267 毫秒
第二次测试:
%%time
a = A()
a.fromDataset(df['labels'])
挂墙时间:249 毫秒
第三次测试:
%%time
b = B()
b.fromDataset(df['labels'])
挂墙时间:220 毫秒
所以...没什么重要的。
已编辑:
事实证明,基础 class 在继承 Tf.keras.Model
的继承树中更高,当此 class 继承存在时,可以观察到下面描述的行为。与普通脚本相比,普通 Python class 的性能可以忽略不计。
我还没有找到任何与此行为相关的文档,如果有可用的更新将随之而来。
编辑 2:
我没有找到任何关于此的文档(因此需要确认),但似乎是:
如果我将任何对象分配给 self
(在继承 class 的 Tf.keras.Model
中),所有包含的 tf.Variables
都将被提取并出现在 trainable_variables
的 [=] 属性中79=]。所以我的假设是 keras.Model
检查对 self
的任何分配,试图找到一些特定的对象,而这种检查导致 self
对一个巨大的 dict 的分配很慢。
供参考:检查深入嵌套列表和字典,但不检查 classes 除非它们扩展 ts.keras.Model
或 tf.keras.Layer
原问题:
我有一个字符串列表 col
(约 30 万行,约 30 个字符的字符串给你一个想法)。准确地说是 pandas.DataGrid
而不是列表。
我正在创建一个查找字典以供将来使用,如下所示:
direct = {}
inverse = {}
# progressive
progressive = 0
# create direct map
for label in col:
# skip if present
if str(label) in direct:
continue
# else add to direct
direct[str(label)] = progressive
inverse[progressive] = str(label)
progressive += 1
这里没有什么奇怪的,它需要 0.15 秒并且 python 进程内存使用是合理的。
然后我将我的代码移到 class 中,这里事情变得奇怪了。这里提供了同一功能的两个略有不同的版本。
版本 A:
def fromDataset(self, column):
# reset map
self.direct = {}
self.inverse = {}
# progressive
progressive = 0
# create direct map
for label in column:
# skip if present
if str(label) in self.direct:
continue
# else add to direct
self.direct[str(label)] = progressive
self.inverse[progressive] = str(label)
progressive += 1
版本 B:
def fromDataset(self, column):
# reset map
direct = {}
inverse = {}
# progressive
progressive = 0
# create direct map
for label in column:
# skip if present
if str(label) in direct:
continue
# else add to direct
direct[str(label)] = progressive
inverse[progressive] = str(label)
progressive += 1
self.direct = direct
self.inverse = inverse
所有建议的函数产生相同的结果(约 120k 个条目的字典,占用约 30MB RAM)
我可以接受版本 A 可能会比版本 B 慢访问 self
变量,但我无法理解的是版本 B 怎么可能花费 2.16 秒(比以前多 14 倍)天气版本 A 甚至无法测试(10 多分钟后还没有结果,进程内存使用量增加了 500+ MB)
更奇怪的是,版本 B 需要 0.17 秒来创建字典,~2 秒来执行:
self.direct = direct
self.inverse = inverse
在为此迷失了整整一天之后,我开始怀疑是否缺少与 Python 内存分配相关的内容。我得出的唯一有意义的假设是 self.direct = direct
导致 Python 实际上 move/copy ram 中的字典。
任何人都可以解释一下版本 A 和版本 B 中发生了什么,这与直接脚本版本有如此根本的不同吗?
我创建了一个可重现的示例并且没有遇到任何问题:
import random
import string
import pandas
def gen_random_word(word_length=30):
return ''.join((random.choice(string.ascii_letters) for _ in range(word_length)))
# I create a list of 300000 labels (but only 150k distinct labels) of 30 characters
labels = [gen_random_word() for _ in range(150000)]
labels = labels + labels
random.shuffle(labels)
# A dataframe here is useless but I try to get close to your own example
df = pandas.DataFrame(
{'labels': labels}
)
class A:
def __init__(self):
self.direct = {}
self.inverse = {}
self.progressive = 0
def fromDataset(self, column):
# create direct map
for label in column:
# skip if present
if str(label) in self.direct:
continue
# else add to direct
self.direct[str(label)] = self.progressive
self.inverse[self.progressive] = str(label)
self.progressive += 1
class B:
def __init__(self):
self.direct = {}
self.inverse = {}
self.progressive = 0
def fromDataset(self, column):
# reset map
direct = {}
inverse = {}
# progressive
progressive = 0
# create direct map
for label in column:
# skip if present
if str(label) in direct:
continue
# else add to direct
direct[str(label)] = progressive
inverse[progressive] = str(label)
progressive += 1
self.direct = direct
self.inverse = inverse
self.progressive = progressive
第一次测试:
%%time # remove that if you are not using jupyter and use another timing solution
direct = {}
inverse = {}
# progressive
progressive = 0
# create direct map
for label in df['labels']:
# skip if present
if str(label) in direct:
continue
# else add to direct
direct[str(label)] = progressive
inverse[progressive] = str(label)
progressive += 1
挂墙时间:267 毫秒
第二次测试:
%%time
a = A()
a.fromDataset(df['labels'])
挂墙时间:249 毫秒
第三次测试:
%%time
b = B()
b.fromDataset(df['labels'])
挂墙时间:220 毫秒
所以...没什么重要的。