在TensorFlow 2中,@tf.function装饰器允许Python函数成为TensorFlow图(或多或少),并可以导致一些性能提升。但是,以这种方式装饰后,Python不再在每次运行时跟踪这些函数。这使得使用Python调试器调试功能更加困难。有没有一种方法可以@tf.function暂时禁用所有装饰器,以便于调试?
解决方案
使用tf.config.experimental_run_functions_eagerly(True)。
tf2+keras,在不使用model.fit的情况下,可以和torch达到同样的效果,就是动态图的效果,数据的流向可以不唯一,模型也可以用tensorboard可视化出来。实际上动态图中用到keras的就只是keras.layer里面的层,例如conv2d,但是动态图的构建方法和torch是一模一样的,你不能直接用model.add,或者keras的函数式来构建模型,而要和torch中类似,现在类的init方法中定义好所有层,然后在call方法中给定数据流动的方向,这里注意,call方法的默认参数是inputs,这个不能变,如果你有多个输入,那应该组合成list或者tuple,一并输入给inputs,然后再在里面解包。有一个非常好理解的例子在https://github.com/Baichenjia/Resnet/blob/master/resnet50.py 这个例子真的让我茅塞顿开。
除了fit和compile方法不能用,keras的summary也没法用,这个功能就是要先建立模型才能输出。否则会报错
File "D:\Anaconda3\envs\tf2\lib\site-packages\tensorflow_core\python\keras\engine\network.py", line 1302, in summary
raise ValueError('This model has not yet been built. '
ValueError: This model has not yet been built. Build the model first by calling `build()` or calling `fit()` with some data, or specify an `input_shape` argument in the first layer(s) for automatic build.
Process finished with exit code 1
原来基于Model对象的方法也都用不了,比如tf.keras.utils.plot_model,这个方法如果给的不是Model(input,output)产生的对象,那么可能输出的只是一张包含函数名的图。
本人对tensorboard是更喜爱的。虽然也写过和用过torch+tensorboardX,但是不大喜欢。唯一的问题是动态图方法的使用导致无法使用fit方法,那么keras用model.fit产生的可爱的进度条也就没了,但是我用tqdm重写了一个,是有效的。其中,bar已经是一个可以迭代的东西,但是附加信息不能动态显示,例如我想像keras一样显示每一个batch的精度,那就得在每次for循环中,通过bar.postfix每次算好了给他也就是了。
不过有一个问题需要注意,第一次前向计算没结束的时候,可还没有精度值呢!也就是说,这个精度显示的其实是上一次的精度,而不是当前这个batch的精度!而且当前这个batch,你还没算呢,怎么可能有精度呢(手动狗头),这不是个技术问题,是个鸡生蛋蛋生鸡的哲学问题。
steps_acc = 0
steps_loss = 0
mmd_loss = torch.tensor(0)
cri_loss = torch.tensor(0)
bar = tqdm(data, total=steps_per_epoch,
desc="a string")
for source_trueColor, source_falseColor, source_dem, \
target_trueColor, target_falseColor, target_dem, \
masks, labels in bar:
bar.postfix = {
'acc': round(steps_acc, 4),
'steps_loss': round(steps_loss, 4),
'mmd_loss': mmd_loss.item(),
'cri_loss': cri_loss.item()
}
下面的错误,原因在于model_final.load_weights(pre_model_path,by_name=True)中的by_name=True,但是如果把by_name=True去掉就会解决这个问题,很奇怪?
Traceback (most recent call last):
File "D:/abc/2-code/fianl_code/pretrain model6/2_预训练分类模型_padding.py", line 100, in
model_final.load_weights(pre_model_path,by_name=True)
File "D:\Anaconda3\envs\tf1\lib\site-packages\tensorflow\python\keras\engine\network.py", line 1514, in load_weights
saving.load_weights_from_hdf5_group_by_name(f, self.layers)
File "D:\Anaconda3\envs\tf1\lib\site-packages\tensorflow\python\keras\engine\saving.py", line 881, in load_weights_from_hdf5_group_by_name
str(weight_values[i].shape) + '.')
ValueError: Layer #97 (named "dense_3"), weight has shape (1536, 20), but the saved weight has shape (60, 20).
Process finished with exit code 1
keras是可以直接用eager模式构建模型的,简单来说就是可以和tensorflow还有pytorch一样,在调试模式下直接看到每一个tensor的值,这个在某些调试过程中非常重要。因为以往写的代码中,都是无法直接采用eager模式运行的,导致有一些问题无法定位,只能通过Keras稍显晦涩的报错来猜,很痛苦,下面这个是github上找到的一个代码,不复杂,但是作为eager的demo绰绰有余,非常完美。
https://github.com/Shathe/MNasNet-Keras-Tensorflow
想要找到用keras实现自己想法的最快方法,就是在github上查相关的关键词,比如本人最近在做半监督相关的网络,就是包括有标签数据和无标签数据,那我就会去查 keras Semi-Supervised 或者 keras Siamese(孪生网络)。因为不一定你想要的东西人家就一定在github上弄好了给你,但是有一些画龙点睛的东西,你看了就知道,原来模型可以这样构建,这就好办多了!
本人在写keras代码的时候,把调用部分,模型,数据生成,loss函数等都分成不同的文件从而减少耦合,也容易定位问题。
但是遇到如下问题:我在模型文件最后对模型进行了实例化(没有放在if main函数中),而模型又是自动命名的,导致在导入模型的时候实例化一遍,在调用模型的时候又调用一遍,而模型中还用了get_layer()函数,于是模型命名就不对了。
下面问题出现的原因是在Model(inputs=input, outputs=output)中,output给的不是tensor,而是由多个tensor组成的列表,这个是不允许的,只能拆开写
Traceback (most recent call last):
File "E:/GraduationThesis/2-code/fianl_code/unet_multilabel_弱监督/unet.py", line 315, in
unet_new(15, 15, 20)
File "E:/GraduationThesis/2-code/fianl_code/unet_multilabel_弱监督/unet.py", line 264, in unet_new
outputs=[output, mid_feature_set])
File "D:\Anaconda3\envs\tf1\lib\site-packages\tensorflow\python\keras\engine\training.py", line 121, in __init__
super(Model, self).__init__(*args, **kwargs)
File "D:\Anaconda3\envs\tf1\lib\site-packages\tensorflow\python\keras\engine\network.py", line 81, in __init__
self._init_graph_network(*args, **kwargs)
File "D:\Anaconda3\envs\tf1\lib\site-packages\tensorflow\python\training\checkpointable\base.py", line 442, in _method_wrapper
method(self, *args, **kwargs)
File "D:\Anaconda3\envs\tf1\lib\site-packages\tensorflow\python\keras\engine\network.py", line 177, in _init_graph_network
self._validate_graph_inputs_and_outputs()
File "D:\Anaconda3\envs\tf1\lib\site-packages\tensorflow\python\keras\engine\network.py", line 1673, in _validate_graph_inputs_and_outputs
'(thus holding past layer metadata). Found: ' + str(x))
ValueError: Output tensors to a Model must be the output of a TensorFlow `Layer` (thus holding past layer metadata). Found: [, , ]
Process finished with exit code 1
今天复盘一个问题,很粗心导致的问题。
模型搭建好了,也能跑,但是精度一直在0.05左右徘徊,然后一直以为是模型构建出了问题,各种找,结果就是不知道问题出在哪。具体表现是:
1/400 [..............................] - ETA: 29:48 - loss: 2.9949 - lr: 0.0010 - part_categorical_crossentropy: 2.9949 - acc: 0.0500 - ca_acc: 0.0500 - kappa: 0.0013 - f1_sc: 0.0500
2/400 [..............................] - ETA: 15:07 - loss: 2.9961 - lr: 0.0010 - part_categorical_crossentropy: 2.9961 - acc: 0.0650 - ca_acc: 0.0650 - kappa: 0.0156 - f1_sc: 0.0650
3/400 [..............................] - ETA: 10:13 - loss: 2.9958 - lr: 0.0010 - part_categorical_crossentropy: 2.9958 - acc: 0.0567 - ca_acc: 0.0567 - kappa: 0.0061 - f1_sc: 0.0567
4/400 [..............................] - ETA: 7:46 - loss: 2.9960 - lr: 0.0010 - part_categorical_crossentropy: 2.9960 - acc: 0.0625 - ca_acc: 0.0625 - kappa: 0.0124 - f1_sc: 0.0625
5/400 [..............................] - ETA: 6:18 - loss: 2.9954 - lr: 0.0010 - part_categorical_crossentropy: 2.9954 - acc: 0.0580 - ca_acc: 0.0580 - kappa: 0.0080 - f1_sc: 0.0580
6/400 [..............................] - ETA: 5:20 - loss: 2.9955 - lr: 0.0010 - part_categorical_crossentropy: 2.9955 - acc: 0.0550 - ca_acc: 0.0550 - kappa: 0.0048 - f1_sc: 0.0550
7/400 [..............................] - ETA: 4:38 - loss: 2.9955 - lr: 0.0010 - part_categorical_crossentropy: 2.9955 - acc: 0.0571 - ca_acc: 0.0571 - kappa: 0.0078 - f1_sc: 0.0571
8/400 [..............................] - ETA: 4:06 - loss: 2.9956 - lr: 0.0010 - part_categorical_crossentropy: 2.9956 - acc: 0.0575 - ca_acc: 0.0575 - kappa: 0.0084 - f1_sc: 0.0575
9/400 [..............................] - ETA: 3:42 - loss: 2.9957 - lr: 0.0010 - part_categorical_crossentropy: 2.9957 - acc: 0.0589 - ca_acc: 0.0589 - kappa: 0.0112 - f1_sc: 0.0589
出现上述问题的原因其实是在数据的生成器中使用了ImageDataGenerator,这里面就有随机性,但是把label给落下了,导致label和数据总也不匹配,从而出现问题。
## 忘了label的
imgs2_tmp = datagen.flow(x=imgs2, batch_size=len(imgs2), shuffle=True, seed=seed,
save_to_dir=None, save_prefix='', save_format='png')
datagen.fit(imgs2, augment=True, seed=seed)
imgs2 = imgs2_tmp.__next__()
## 加了label的
imgs2_tmp = datagen.flow(x=imgs2, y=labels, batch_size=len(imgs2), shuffle=True, seed=seed, save_to_dir=None, save_prefix='', save_format='png')
datagen.fit(imgs2)
imgs2, labels = imgs2_tmp.__next__()
遇到如下问题的原因:已经用add_loss了,然后在compile中还给loss,就会出问题
final_model.compile(
loss='categorical_crossentropy'
)
2021-02-06 16:43:11.935617: I tensorflow/stream_executor/dso_loader.cc:152] successfully opened CUDA library cublas64_100.dll locally
Traceback (most recent call last):
File "E:/GraduationThesis/2-code/fianl_code/oneLabel_弱监督/2_语义分割_padding_multiLabel_加载预训练.py", line 240, in
use_multiprocessing=False,
File "D:\Anaconda3\envs\tf1\lib\site-packages\tensorflow\python\keras\engine\training.py", line 737, in fit
initial_epoch=initial_epoch)
File "D:\Anaconda3\envs\tf1\lib\site-packages\tensorflow\python\keras\engine\training.py", line 1426, in fit_generator
initial_epoch=initial_epoch)
File "D:\Anaconda3\envs\tf1\lib\site-packages\tensorflow\python\keras\engine\training_generator.py", line 225, in model_iteration
mode='test')
File "D:\Anaconda3\envs\tf1\lib\site-packages\tensorflow\python\keras\engine\training_generator.py", line 191, in model_iteration
batch_outs = batch_function(*batch_data)
File "D:\Anaconda3\envs\tf1\lib\site-packages\tensorflow\python\keras\engine\training.py", line 1256, in test_on_batch
outputs = self._eval_function(inputs) # pylint: disable=not-callable
File "D:\Anaconda3\envs\tf1\lib\site-packages\tensorflow\python\keras\backend.py", line 3076, in __call__
run_metadata=self.run_metadata)
File "D:\Anaconda3\envs\tf1\lib\site-packages\tensorflow\python\client\session.py", line 1439, in __call__
run_metadata_ptr)
File "D:\Anaconda3\envs\tf1\lib\site-packages\tensorflow\python\framework\errors_impl.py", line 528, in __exit__
c_api.TF_GetCode(self.status.status))
tensorflow.python.framework.errors_impl.InvalidArgumentError: You must feed a value for placeholder tensor 'lambda_1_target' with dtype float and shape [?,?,?,?]
[[{{node lambda_1_target}}]]
[[{{node div_no_nan_21}}]]
Process finished with exit code 1
如果有一个分支不想给标签,不想做监督训练,但是又不能不要。因为如果在
Model(inputs=input, outputs=[output_1, output_2])中不加上output_2,就会导致和output_2相关的分支全都不见了,没有编译到模型中。
如果我又想保留这个分支,就需要如下这种鸡贼巧妙的方法
output = Lambda(lambda x: x[0])([output, target_output, input_mask])
模型 compile 之后再加add_loss就不管用了,所以一定只能在最后用compile
复用结构 想要用mmd计算中间层输出的差异,可以让Model的输出就包括那个中间层,这样就可以用out,mid = model(input)
下面问题的原因之一:输入包括多个input,loss又给的是默认的,就是model.compile(loss=loss),导致模型不知道怎么算梯度,导致出错。需要自定义loss函数,然后用add_loss函数给加进去
ValueError: An operation has `None` for gradient. Please make sure that all of your ops have a gradient defined (i.e. are differentiable). Common ops without gradient: K.argmax, K.round, K.eval.
如果出现如下错误,原因是我们已经把label作为input输入到模型中,用来自己给定loss和评价指标,这种情况下就不需要再在生成器中给定y,格式就是:
## 第一种方法
yield ({'input_1': imgs[:, :, :, -1:0:-1],
'input_mask': masks, 'input_label': labels}, None)
## 第二种方法,可以直接丢掉None,**但是逗号绝对不能丢**,因为有逗号代表这是两个元素的tuple,没有逗号就是一个元素的tuple
yield ({'input_1': imgs[:, :, :, -1:0:-1],
'input_mask': masks, 'input_label': labels}, )
D:\Anaconda3\envs\tf1\lib\site-packages\keras_preprocessing\image\numpy_array_iterator.py:127: UserWarning: NumpyArrayIterator is set to use the data format convention "channels_last" (channels on axis 3), i.e. expected either 1, 3, or 4 channels on axis 3. However, it was passed an array with shape (1, 15, 15, 20) (20 channels).
str(self.x.shape[channels_axis]) + ' channels).')
Traceback (most recent call last):
File "E:/GraduationThesis/2-code/fianl_code/multiLabel_弱监督/2_语义分割_padding_multiLabel_加载预训练.py", line 240, in
use_multiprocessing=False,
File "D:\Anaconda3\envs\tf1\lib\site-packages\tensorflow\python\keras\engine\training.py", line 737, in fit
initial_epoch=initial_epoch)
File "D:\Anaconda3\envs\tf1\lib\site-packages\tensorflow\python\keras\engine\training.py", line 1426, in fit_generator
initial_epoch=initial_epoch)
File "D:\Anaconda3\envs\tf1\lib\site-packages\tensorflow\python\keras\engine\training_generator.py", line 191, in model_iteration
batch_outs = batch_function(*batch_data)
File "D:\Anaconda3\envs\tf1\lib\site-packages\tensorflow\python\keras\engine\training.py", line 1175, in train_on_batch
x, y, sample_weight=sample_weight, class_weight=class_weight)
File "D:\Anaconda3\envs\tf1\lib\site-packages\tensorflow\python\keras\engine\training.py", line 2421, in _standardize_user_data
exception_prefix='target')
File "D:\Anaconda3\envs\tf1\lib\site-packages\tensorflow\python\keras\engine\training_utils.py", line 283, in standardize_input_data
'expected no data, but got:', data)
ValueError: ('Error when checking model target: expected no data, but got:', array([[[[0., 0., 0., ..., 1., 0., 0.],
[0., 0., 0., ..., 1., 0., 0.],
[0., 0., 0., ..., 1., 0., 0.],
...,
[0., 0., 0., ..., 1., 0., 0.],
[0., 0., 0., ..., 1., 0., 0.],
[0., 0., 0., ..., 1., 0., 0.]],
[[0., 0., 0., ..., 1., 0., 0.],
[0., 0., 0., ..., 1., 0., 0.],
[0., 0., 0., ..., 1., 0., 0.],
...,
[0., 0., 0., ..., 1., 0., 0.],
[0., 0., 0., ..., 1., 0., 0.],
[0., 0., 0., ..., 1., 0., 0.]],
[[0., 0., 0., ..., 1., 0., 0.],
[0., 0., 0., ..., 1., 0., 0.],
[0., 0., 0., ..., 1., 0., 0.],
...,
[0., 0., 0., ..., 1., 0., 0.],
[0., 0., 0., ..., 1., 0., 0.],
[0., 0., 0., ..., 1., 0., 0.]],
...,
[[0., 0., 0., ..., 1., 0., 0.],
[0., 0., 0., ..., 1., 0., 0.],
[0., 0., 0., ..., 1., 0., 0.],
...,
[0., 0., 0., ..., 1., 0., 0.],
[0., 0., 0., ..., 1., 0., 0.],
[0., 0., 0., ..., 1., 0., 0.]],
[[0., 0., 0., ..., 1., 0., 0.],
[0., 0., 0., ..., 1., 0., 0.],
[0., 0., 0., ..., 1., 0., 0.],
...,
[0., 0., 0., ..., 1., 0., 0.],
[0., 0., 0., ..., 1., 0., 0.],
[0., 0., 0., ..., 1., 0., 0.]],
[[0., 0., 0., ..., 1., 0., 0.],
[0., 0., 0., ..., 1., 0., 0.],
[0., 0., 0., ..., 1., 0., 0.],
...,
[0., 0., 0., ..., 1., 0., 0.],
[0., 0., 0., ..., 1., 0., 0.],
[0., 0., 0., ..., 1., 0., 0.]]]], dtype=float32))
Process finished with exit code 1
keras模型构建如果遇到 ‘Model’ object has no attribute ‘_name’ ,
通常是因为 输入变量被改动了 举个例子
本来 a = Input()
b = Conv2D()(a)
如果写成了 a = Input()
a = Conv2D()(a)
那么,在使用 model = Model(inputs=[a], outputs=[b])就会产生上述问题
keras模型构建中,如果用get_layer(name=""),必须确保 层名 是真实有效的。今天用的时候就一直报错,说找不到对应层,我以为是 每个层即使自定义name也会在后面加上 /Relu:0 但其实不是这样的!!,自定义的名字后面不会有系统添加的后缀。
产生这样问题的原因真的是模型中没有这个名字的层,那么命名代码中有定义,为什么却找不到这一层呢?答案只有一个,就是这一层压根就没有被构建到模型中去。
keras模型构建过程中,model.compile中的input和output必须要写全,如果光定义了input,没有给出相应的output,那么这一个output对应的分支就算没有定义,不会被构建到模型中去,谨记
指定显卡
os.environ[“CUDA_VISIBLE_DEVICES”] = ”0,2,3“
model.add_metrics 增加输出到终端的指标
model.add_loss 增加loss指标(注意,如果给了多个loss指标,keras默认会把所有的loss值加在一起回传,如果想要做复杂的loss函数,例如动态给不同loss函数权重,这种需要设置唯一的一个loss函数,实现所要的功能,注意,这种情况下add_loss一定只能调用一次!)
sklearn中有很多指标,但是没有办法直接放到keras模型中,因为keras模型要求输入tensor,而sklearn输入的是numpy数组,因此要用如下函数把sklearn的函数做一个映射转换,这样就可以直接在模型训练过程中输出出来。
tf.py_func(f1_score_, (true_mask_argmax, pred_mask_argmax), tf.double)
keras 如果使用了tensorflow.python.confusion_matrix,输入一定是非独热编码的tensor,否则会报错。要用tf.reduce_sum tf.reduce_max等,不能直接用numpy的了。
如果出现如下错误,是因为给tensorflow.python.confusion_matrix指定了num_classes,改成num_classes=None也不行2333,目前没有找到解决办法,但是因为这个问题是我为了在训练过程中输出iou值导致的,其实不是很重要,因此先搁置,不在训练过程中输出这个指标即可
找到原因:本来人家代码用np.diag返回对角向量列表,结果tf.diag返回的是对角矩阵。因此出错,只要改成 tf.linalg.tensor_diag_part(confusionMatrix)就可以返回对角矩阵的一维tensor,下面的错误也就不复存在了欧耶
File "D:\Anaconda3\envs\tf1\lib\site-packages\tensorflow\python\keras\engine\training.py", line 737, in fit
initial_epoch=initial_epoch)
File "D:\Anaconda3\envs\tf1\lib\site-packages\tensorflow\python\keras\engine\training.py", line 1426, in fit_generator
initial_epoch=initial_epoch)
File "D:\Anaconda3\envs\tf1\lib\site-packages\tensorflow\python\keras\engine\training_generator.py", line 191, in model_iteration
batch_outs = batch_function(*batch_data)
File "D:\Anaconda3\envs\tf1\lib\site-packages\tensorflow\python\keras\engine\training.py", line 1191, in train_on_batch
outputs = self._fit_function(ins) # pylint: disable=not-callable
File "D:\Anaconda3\envs\tf1\lib\site-packages\tensorflow\python\keras\backend.py", line 3076, in __call__
run_metadata=self.run_metadata)
File "D:\Anaconda3\envs\tf1\lib\site-packages\tensorflow\python\client\session.py", line 1439, in __call__
run_metadata_ptr)
File "D:\Anaconda3\envs\tf1\lib\site-packages\tensorflow\python\framework\errors_impl.py", line 528, in __exit__
c_api.TF_GetCode(self.status.status))
tensorflow.python.framework.errors_impl.InvalidArgumentError: Incompatible shapes: [19] vs. [19,20,20,20]
[[{{node mul_10}}]]
如果生成器输出的形状变成了(n, ),那一定是这一批数据中有一个数据的形状和其他的不一样,例如,正常都是(32,51,51,2) 如果其中有一个数据是(50,51,2)或者直接就是(0,51,2),那么该批次的形状就是(32,)
如果模型输出的大小或格式(例如是否独热编码)与给的标签不同,那么有两种可能的状况,第一种是能够训练,但是精度都是nan;第二种是产生一个关于形状错误的提示,目前无法复现了。大致就是,本来需要(32,15,15,20)的输出,结果给了一个(32,1,12,19)这种奇形怪状,找了很多方法都没解决,后来发现是语义分割模型最后的输出大小与输入不同,上采样层少了一个导致的。
kerasm中,如果有lambda层,就没办法用model.to_json或者to_ymal函数,会出现如下错误,目前没有找到解决办法
TypeError: (‘Not JSON Serializable:’, TensorShape([Dimension(None), Dimension(12), Dimension(12), Dimension(48)]))
keras AttributeError: ‘Model’ object has no attribute ‘total_loss’
该问题是因为模型构建完成没有model.compile导致的
keras中,如果把某一层的 name属性赋值,则会导致相同类型的层默认命名产生变化,比如把第一个maxpool层重命名为max_1,则下一个池化层会默认命名为 maxpool_1(keras默认分配的),这一点在load_weight(by_name=True)的时候尤其注意,否则会导致权重没有正确加载
需要每个支路都在最后用model=Model(inputs=input,outputs=output),然后return这个model(属于Model实例),然后使用model.output连接下面的网络层,例如keras.layers.Concatenate()([model1.output,model2.output])来得到下一层,其中,model.output实际上是tensor实例。
def network(input_size):
input = Input(shape=(input_size,input_size,1))
block1 = Conv2D(128,(3,3))(input)
model = Model(inputs=input,outputs=block1)
return model
net1 = network(128)
net2 = network(128)
a = net1.output
b = net2.output
c = keras.layers.Concatenate(axis=-1)([a,b])
output = Dense(100)(c)
model = Model(inputs=[net1.input,net2.input],outputs=output)
def network(input):
block1 = Conv2D(128,(3,3))(input)
return block1
input1 = Input((128,128,1))
input2 = Input((128,128,1))
net1 = network(input1)
net2 = network(input2)
net = keras.layers.Concatenate(axis=-1)([net1,net2])
output = Dense(100)(net)
model = Model(inputs=[input1,input2],outputs=output)
如果只是同一支路内部的网络封装,则不需要写Model,直接return最后那一层就可以了。
实际上,在keras中,每个层接收和输入都是tensor,相当于tensor在不同的层中间流动。