keras2onnx出现onnx_cpp2py_export.cpython-35m-x86_64-linux-gnu.so: undefined symbol: _ZNK6google8protobuf7Message11GetTypeNameEv
protobuf版本太低升级到3.6.1 参照链接
https://blog.csdn.net/kdchxue/article/details/81046192
更新protobuf版本之后还是不行,使用一下命令查找链接的位置
ldd onnx_cpp2py_export.cpython-35m-x86_64-linux-gnu.so
发现还是和之前一样,应该是系统现在有两个版本的protobuf,安装onnx的时候自动链接到了低版本。于是将onnx卸载,使用以下命令将新版本的protobuf被优先搜索
export LD_LIBRARY_PATH=/usr/local/bin/protoc:$LD_LIBRARY_PATH
重新安装onnx即可,记得要清楚缓存安装哦
附上linux 下 动态库搜索路径优先顺序:
1.编译目标代码时指定的动态库搜索路径;
2.环境变量LD_LIBRARY_PATH指定的动态库搜索路径;
3.配置文件/etc/ld.so.conf中指定的动态库搜索路径;//配置后要运行 ldconfig命令才能生效
4.默认的动态库搜索路径/lib;
5.默认的动态库搜索路径/usr/lib;
迁移学习中,keras框架如何载入部分权重
classifier_names = ['conv4_3_norm_mbox_conf',
'fc7_mbox_conf',
'conv6_2_mbox_conf',
'conv7_2_mbox_conf',
'conv8_2_mbox_conf',
'conv9_2_mbox_conf'] # 通常情况由于类别数量变化导致shape不匹配
f = h5py.File(weights_path, mode='r')
if 'layer_names' not in f.attrs and 'model_weights' in f:
f = f['model_weights']
layers = model.inner_model.layers if hasattr(model, "inner_model") \
else model.layers
# Exclude some layers
layers = filter(lambda l: l.name not in classifier_names, layers)
saving.load_weights_from_hdf5_group_by_name(f, layers) #如果是keras=2.0.8 这里的saving替换为from keras.engine import topology
if hasattr(f, 'close'):
f.close()
tf新接触的函数
# tf.boolean_mask
# 1-D example
tensor = [0, 1, 2, 3]
mask = np.array([True, False, True, False])
boolean_mask(tensor, mask) # [0, 2]
# 2-D example
tensor = [[1, 2], [3, 4], [5, 6]]
mask = np.array([True, False, True])
boolean_mask(tensor, mask) # [[1, 2], [5, 6]]
tf.logical_and(True, False))
tf.logical_or(True, False))
tf.pad,这幅图表达的比较清晰
千万不要使用tf.map_fn,之前有一个网络复现使用了该函数,导致训练会非常慢,知乎上看到一个解释:
熟悉functional programming的朋友们都知道,函数式编程有利于高度并行的计算。当我们看到map_fn时不禁会认为它必然会提供一种高效的并行机制,但事实却恰恰相反。在内部实现中,map_fn调用了tf.while_loop,使得并行计算非常困难。这个问题可以通过使用timeline的profile发现。为了避免低效的map_fn,在一些问题中,如果我们希望对某一个维度进行map的操作,可以先对原tensor进行reshape,将map维度融合入batch维度,操作完成后再将该tensor reshape回来。
1.keras使用已经训练好的模型,增加一个新的分支,保持之前网络权重不变。
def get_keras_model():
adam = optimizers.adam(lr=0.0005)
input_tensor = Input((224, 224, 3)) #模型的输入
label = Input((1,)) #需要训练分支的label
mobile_out = MobileNetV2(input_shape=(224, 224, 3), pooling='avg', include_top=False)(input_tensor) #backbone
dense = Dense(units=36, kernel_initializer="he_normal",
activation="softmax", trainable=False)(mobile_out) #已经训练好的全连接分支,所以要增加trainable=False
dense_goutu = Dense(units=5, kernel_initializer="he_normal",
activation="softmax", name='XXX')(mobile_out) #新增加的全连接层
loss = K.mean(losses.sparse_categorical_crossentropy(label, dense_goutu)) #自定义loss
acc = K.mean(metrics.sparse_categorical_accuracy(label, dense_goutu))
model = Model(inputs=[input_tensor, label], outputs=[dense_goutu, dense])
model.add_loss(loss)
model.layers[1].trainable = False #提取特征网络的权重不变
model.compile(loss=[None, None], optimizer=adam, metrics=['accuracy']) # 设置虚拟损失
model.metrics_tensors.append(acc)
model.metrics_names.append('acc')
return model
训练之前先载入权重
model.load_weights('XXXXXX', by_name=True) # by_name=True 这个参数一定要加
另外数据生成器也要改,按照下面的形式传递给模型训练。
yield [batch_img, batch_label], None
2.关于torch.nn.Linear的权重shape一点疑问
import torch
a = torch.randn(60, 30) #
b = torch.nn.Linear(30, 15) # 但是b的weight的shape是[15,30]
output = b(a) #猜测是Linear会对权重做转置
print('b.weight.shape:\n ', b.weight.shape)
print('b.bias.shape:\n', b.bias.shape)
print('output.shape:\n', output.shape)
ans = torch.mm(a, b.weight.t()) + b.bias #这里也是将b转置才可以计算,结果和上面是一致的.
print('ans.shape:\n', ans.shape)
print(torch.equal(ans, output))
3.当训练神经网络出bug的时候导致僵尸进程
在神经网络训练中,如果程序没有正常退出,尤其是多卡的时候,会导致僵尸进程出现,正常情况其实僵尸进程影响不大。但是由深度学习导致的僵尸进程会占用显存,导致无法训练。
ps -ef | grep defunct
前三列分别是UID、PID、PPID
然后就开始一个一个杀把。 如果还不能解决问题,就重启把
还有一种情况是,nvidia-smi 的时候没有看到该进程,但是上面的显存却实际被占用,遇到这种情况使用
fuser -v /dev/nvidia*
然后就看到占用显存的进程直接杀掉就可以了
4.输入尺寸和生成的尺寸匹配,却Incompatible shapes
- metrics=['accuracy'] 去掉就可以了, 这其实是2.2.4版本的bug,可以选择降级。
5.Tensorflow结合Flask部署的时候的一些使用方法.
5.1 部署Tensorflow模型的时候最好是将模型持久化,不要每次预测的时候都要模型初始化。预先载入模型的时候,最好使用tf.Session().as_default()
tf.Session() #创建一个会话,当上下文管理器退出时会话关闭和资源释放自动完成。
tf.Session().as_default()创建一个默认会话,当上下文管理器退出时会话没有关闭,还可以通过调用会话进行run()和eval()操作
tf通过运行时维护的session本地线程栈,来管理默认session。故不同的线程会有不同的默认session,默认session是线程作用域的。一个Session只能run一个Graph,但一个Graph可以运行在多个Session中。常见情况是,session会运行全局唯一的隐式的默认的Graph,operation也是注册到这个Graph中。也可以显示创建Graph,并调用as_default()使他替换默认Graph。在该上下文管理器中创建的op都会注册到这个graph中。退出上下文管理器后,则恢复原来的默认graph。一般情况下,我们不用显式创建Graph,使用系统创建的那个默认Graph即可。
5.2同时部署多TF模型用于Web服务
因为tf的graph的机制,不同模型要放在不同graph下面去初始化。如果使用加载单个模型的方式去加载多个模型,那么就会出现变量冲突的错误,也无法工作。这个问题的原因是因为一个默认图的缘故。冲突的发生是因为我们将所有变量都加载到当前会话采用的默认图中。当我们采用会话的时候,我们可以通过tf.Session(graph=MyGraph)来指定采用不同的已经创建好的图。因此,如果我们希望加载多个模型,那么我们需要做的就是把他们加载在不同的图,然后在不同会话中使用它们。相同的网络结构和不同的网络结构都可以适用,下面我放一个相同结构的例子。
class StyleTrans(object):
def __init__(self, path):
self.graph = tf.Graph()
with self.graph.as_default():
# if 1==1:
self.img_placeholder = tf.placeholder(tf.float32, shape=[1, None, None, 3],
name='img_placeholder')
self.rows_1 = tf.placeholder(tf.int32,
name='rows_1')
self.cols_1 = tf.placeholder(tf.int32,
name='cols_1')
self.rows_2 = tf.placeholder(tf.int32,
name='rows_2')
self.cols_2 = tf.placeholder(tf.int32,
name='cols_2')
self.preds = src.inf_transform.net(self.img_placeholder, self.rows_1, self.cols_1, self.rows_2, self.cols_2)
ckpt = tf.train.get_checkpoint_state(path)
saver = tf.train.Saver()
soft_config = tf.ConfigProto(allow_soft_placement=True)
soft_config.gpu_options.allow_growth = True
self.sess = tf.Session(config=soft_config, graph=self.graph)
with self.sess.as_default():
with self.graph.as_default():
saver.restore(self.sess, ckpt.model_checkpoint_path)
然后可以实例化多个不同权重的模型
5.3关于tensorflow的显存占用问题
随便记录下观察结果(也不一定对)
如果tensorflow和pytorch 同时初始化在一个GPU中,会导致tensorflow变慢
但是让tensorflow先初始化,问题可能会得到改善
都知道tensorflow如果不限制,会把显存吃满,导致其他框架的模型无法初始化。有个比较奇特的一点,对每一个模型限制内存后 ,两个相同参数量tensorflow模型都初始化完毕后显存占用却和一个差不多,看起来是相同计算框架下面可以共存部分。但是如果不限制,会直接初始化失败,就不能共存。
如果有相关研究比较深入的,望讲解一下,谢谢
6.Pytorch载入模型时UnicodeDecodeError
这是由于模型是在python2训练出来的,由于编码问题在python3导致无法读取。 我们使用pickle做跳转
解决办法:
先在python2:
checkpoint = torch.load("path")
with open("path", 'wb') as f:
pickle.dump(checkpoint,f)
#回到py3
pkl_file = open('path','rb')
data = pickle.load(pkl_file, encoding='latin1')
torch.save(data, "path")
7.深度学习模型不同环境值输出不一样
最近写了个神经网络推断脚本,发现在不同的工作站的输出值略有差异,开始以往以为是读取数据或者传输数据出现了什么问题,测试了很久也没有发现。最后写了个更简单的脚本直接在两台机器上测试发现值不一样,这样只能是环境导致的了。 但是我用 pip list 发现环境都一样的。 然后仔细看了一下waring(waring我基本都不注意的。。),发现可能skimage 有关。然后我对比了两台工作站的skimage 发现版本还是一样的。我在程序中发现一个 是 0.15. 一个是0.14.2 。和pip list显示的有所不一样。 把0.14.2 连续 pip uninstall scikit-image 后 重新装0.15,两台工作站的输出值就一样了。 我也测试了0.13版本的 发现和0.14的是一样的。
8.TypeError: new() got an unexpected keyword argument 'serialized_options'
应该是这个protobuf出了问题,卸载当前版本,
我自己试了一下 这个版本是可以的
pip install protobuf==3.7.1 -i https://pypi.tuna.tsinghua.edu.cn/simple
9.如何在tensorflow计算图定义批量计算线距离的op
假设某几根线是label,要和若干线计算距离,当然也可以两两计算,思路是差不多的。
tf.reshape(tf.tile(label,[1,line_num]),[line_num*lable_num,4])
tf.tile(line,[label_num,1])
两个矩阵的复制的方向是不一样的,大家注意了
这样两个矩阵就是相同的shape了
然后再用tf.squared_difference 就可以啦
大家有什么好的想法也可以交流下。
10.numpy or 在tensorflow图下如何判断矩阵中某值的个数
比如要在矩阵得到大于1的个数可以用以下:
np.sum(martix>0.5).astype(int))
意思就是先成一个bool值的矩阵然后转换数据类型就成0,1 然后求和。
在tensorflow:
tf.reduce_sum(tf.cast(martix
可以用在计算图下定义根据满足条件来生成gt label。
11.如何写tensorflow和keras的数据生成器用于训练.
class DataSet(object):
def __init__(self, X,Y, batch_size):
self.X = np.array(X)
self.Y = np.array(Y)
self.batch_per_epcoh = len(self.X) //self.batch_size
self.all_num = len(self.X)
def __call__(self):
while True:
shuffle_idx = np.random.permutation(self.all_num)
for i_batch in range(self.batch_per_epcoh):
batch_id = shuffle_idx[i_batch * self.batch_size:(i_batch + 1) * self.batch_size]
batch_img_path = self.X[batch_id]
batch_img = np.zeros([self.batch_size, 224, 224, 3])
batch_label = self.Y[batch_id]
for num, path in enumerate(batch_img_path):
img = cv2.resize(cv2.imread(path), (224, 224))
image = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
batch_img[num] = image.astype(np.float32) / 255
yield [batch_img, batch_label], None
def __len__(self):
return self.batch_per_epcoh
100.caffe :ValueError: Mean shape incompatible with input shape.
当出现这个问题的时候,看一下报错的提示找到io.py,我的是在这里:/miniconda3/envs/tensorflow/lib/python3.6/site-packages/caffe/io.py
然后
253-254行
if ms != self.inputs[in_][1:]:
raise ValueError('Mean shape incompatible with input shape.')
替换为
if ms != self.inputs[in_][1:]:
print(self.inputs[in_])
in_shape = self.inputs[in_][1:]
m_min, m_max = mean.min(), mean.max()
normal_mean = (mean - m_min) / (m_max - m_min)
mean = resize_image(normal_mean.transpose((1,2,0)),in_shape[1:]).transpose((2,0,1)) * (m_max - m_min) + m_min