将二维稀疏矩阵转换为三维矩阵

我想把二维稀疏矩阵转换为三维矩阵,因为我需要给它输入conv1d层,而conv1d层期望的是三维张量。

下面是conv1d层的输入。

from scipy.sparse import hstack
other_features_train = hstack((X_train_state_ohe, X_train_teacher_ohe, X_train_grade_ohe, X_train_category_ohe, X_train_subcategory_ohe,X_train_price_norm,X_train_number_norm))
other_features_cv = hstack((X_cv_state_ohe, X_cv_teacher_ohe, X_cv_grade_ohe,X_cv_category_ohe,X_cv_subcategory_ohe,X_cv_price_norm,X_cv_number_norm))
other_features_test = hstack((X_test_state_ohe, X_test_teacher_ohe, X_test_grade_ohe,X_test_category_ohe,X_test_subcategory_ohe,X_test_price_norm,X_test_number_norm))

print(other_features_train.shape)
print(other_features_cv.shape)
print(other_features_test.shape)

训练、CV和测试数据的形状。

(49041, 101)
(24155, 101)
(36052, 101)

这是我的模型架构。

tf.keras.backend.clear_session()

vec_size = 300

input_model_1 = Input(shape=(300,),name='essay')
embedding = Embedding(vocab_size_essay, vec_size, weights=[word_vector_matrix], input_length = max_length, trainable=False)(input_model_1)
lstm = LSTM(16)(embedding)
flatten_1 = Flatten()(lstm)

input_model_2 = Input(shape=(101, ),name='other_features')
conv_layer1 = Conv1D(32, 3, strides=1, padding='valid', kernel_initializer='glorot_uniform', activation='relu')(input_model_2)
conv_layer2 = Conv1D(32, 3, strides=1, padding='valid', kernel_initializer='glorot_uniform', activation='relu')(conv_layer1)
conv_layer3 = Conv1D(32, 3, strides=1, padding='valid', kernel_initializer='glorot_uniform', activation='relu')(conv_layer2)
flatten_2 = Flatten()(conv_layer3)

concat_layer = concatenate(inputs=[flatten_1, flatten_2],name='concat')

dense_layer_1 = Dense(units=32, activation='relu', kernel_initializer='he_normal', name='dense_layer_1')(concat_layer)

dropout_1 = Dropout(0.2)(dense_layer_1)

dense_layer_2 = Dense(units=32, activation='relu', kernel_initializer='he_normal', name='dense_layer_2')(dropout_1)

dropout_2 = Dropout(0.2)(dense_layer_2)

dense_layer_3 = Dense(units=32, activation='relu', kernel_initializer='he_normal', name='dense_layer_3')(dropout_2)

output = Dense(units=2, activation='softmax', kernel_initializer='glorot_uniform', name='output')(dense_layer_3)

model_3 = Model(inputs=[input_model_1,input_model_2],outputs=output)

当我试图给出二维数组时,得到这个错误。

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-18-44c8f6f0caa7> in <module>
      9 
     10 input_model_2 = Input(shape=(101, ),name='other_features')
---> 11 conv_layer1 = Conv1D(32, 3, strides=1, padding='valid', kernel_initializer='glorot_uniform', activation='relu')(input_model_2)
     12 conv_layer2 = Conv1D(32, 3, strides=1, padding='valid', kernel_initializer='glorot_uniform', activation='relu')(conv_layer1)
     13 conv_layer3 = Conv1D(32, 3, strides=1, padding='valid', kernel_initializer='glorot_uniform', activation='relu')(conv_layer2)

~\AppData\Local\Programs\Python\Python37\lib\site-packages\tensorflow_core\python\keras\engine\base_layer.py in __call__(self, inputs, *args, **kwargs)
    810         # are casted, not before.
    811         input_spec.assert_input_compatibility(self.input_spec, inputs,
--> 812                                               self.name)
    813         graph = backend.get_graph()
    814         with graph.as_default(), backend.name_scope(self._name_scope()):

~\AppData\Local\Programs\Python\Python37\lib\site-packages\tensorflow_core\python\keras\engine\input_spec.py in assert_input_compatibility(input_spec, inputs, layer_name)
    175                          'expected ndim=' + str(spec.ndim) + ', found ndim=' +
    176                          str(ndim) + '. Full shape received: ' +
--> 177                          str(x.shape.as_list()))
    178     if spec.max_ndim is not None:
    179       ndim = x.shape.ndims

ValueError: Input 0 of layer conv1d is incompatible with the layer: expected ndim=3, found ndim=2. Full shape received: [None, 101]

model_3.summary()
model_3.compile(loss = "binary_crossentropy", optimizer=Adam()

编译模型

model_3.compile(loss = "binary_crossentropy", optimizer=Adam(), metrics=["accuracy"])

拟合模型

model_3.fit(train_features,y_train_ohe,batch_size=16,epochs=10,validation_data=(cv_features,y_cv_ohe))

train_features = [train_text, other_features_train]
cv_features = [cv_text, other_features_cv]
test_featues = [test_text, other_features_test]

文本特征

train_text = X_train['essay'].tolist()
cv_text = X_cv['essay'].tolist()
test_text = X_test['essay'].tolist()

token = Tokenizer()
token.fit_on_texts(train_text)

vocab_size_essay = len(token.word_index) + 1
print("No. of unique words = ", vocab_size_essay)

encoded_train_text = token.texts_to_sequences(train_text)
encoded_cv_text = token.texts_to_sequences(cv_text)
encoded_test_text = token.texts_to_sequences(test_text)

#print(encoded_test_text[:5])

max_length = 300

train_text = pad_sequences(encoded_train_text, maxlen=max_length, padding='post')
cv_text = pad_sequences(encoded_cv_text, maxlen=max_length, padding='post')
test_text = pad_sequences(encoded_test_text, maxlen=max_length, padding='post')

print("\n")
print(train_text.shape)
print(cv_text.shape)
print(test_text.shape)

字形

No. of unique words =  41468


(49041, 300)
(24155, 300)
(36052, 300)

所以,我想在

(49041,101,1) 
(24155,101,1) 
(36052,101,1) 

请建议如何做。

1
投票

解决方法

这里的解决方案要求明确以下几个概念。我将在下面的章节中解释这些概念。

什么 keras 期望作为输入 哪些修改可以对你的 keras 模型,以允许稀疏的输入矩阵。 转换二维 numpy 阵列到一个3D numpy 阵列 稀疏数组和非稀疏数组(或密集数组)之间的前后转换,使用的是 scipy.sparse.coo_matrix 对于二维 numpy 阵列 sparse.COO 用于三维 numpy 阵列

使用稀疏矩阵作为输入到 tf.keras 模型

其中一个选择是将您的稀疏输入矩阵转换成非稀疏(密集)格式,使用 todense() 方法。这使得矩阵成为一个规则的 numpy 数组。见kaggle讨论。[3] 和 [4].

另一个选择是通过子类,为稀疏和密集输入写你自己的自定义Layers tf.keras.layers.Layer 类。见本条。[2].

tensorflow.keras现在似乎允许使用稀疏权重进行模型训练。所以,在某个地方它有能力处理稀疏性。你可能想探索一下文档,[]。1]来实现这方面的功能。

在numpy数组中添加新轴

你可以使用以下方法向一个numpy数组添加另一个轴 np.newaxis 如下所示。

import numpy as np

## Make a 2D array
a2D = np.zeros((10,10))

# Make a few elements non-zero in a2D
aa = a2D.flatten()
aa[[0,13,41,87,98]] = np.random.randint(1,10,size=5)
a2D = aa.reshape(a2D.shape)

# Make 3D array from 2D array by adding another axis
a3D = a2D[:,:,np.newaxis]
#print(a2D)
print('a2D.shape: {}\na3D.shape: {}'.format(a2D.shape, a3D.shape))

产出:

a2D.shape: (10, 10)
a3D.shape: (10, 10, 1)

说到这里,请看一下《世界日报》中的链接。参考文献 节。

稀疏数组

由于稀疏数组的非零值非常少,所以常规的numpy数组转换成稀疏数组后,会以几种稀疏格式存储。

csr_matrix:非零值和索引的行数组 csc-matrix:非零值和指数的列式数组。 coo-matrix一张有三栏的表格 行 专栏 非零值

Scipy Sparse Matrices期待2D输入矩阵。

然而, scipy.sparse 以上三类稀疏矩阵的实现,只考虑2D非稀疏矩阵作为输入。

from scipy.sparse import csr_matrix, coo_matrix

coo_a2D = coo_matrix(a2D)
coo_a2D.shape # output: (10, 10)

# scipy.sparse only accepts 2D input matrices
# the following line will through an !!! ERROR !!!
coo_a3D = coo_matrix(coo_a2D.todense()[:,:,np.newaxis])

由三维非稀疏输入矩阵得到稀疏矩阵。

是的,您可以使用 sparse 库。它还支持 scipy.sparsenumpy 数组。要从稀疏矩阵转换为非稀疏(密)格式(这不是神经网络中的密集层。),使用 todense() 方法。

## Installation
# pip install -U sparse

import sparse

## Create sparse coo_matrix from a 
# 3D numpy array (dense format)
coo_a3D = sparse.COO(a3D)

## Test that 
#   coo_a3D == coo made from (coo_a2D + newaxis)
print(
    (coo_a3D == sparse.COO(coo_a2D.todense()[:,:,np.newaxis])).all()
) # output: True
## Convert to dense (non-sparse) format 
#   use: coo_a3D.todense()
print((a3D == coo_a3D.todense()).all()) # output: True

scipy.sparse.coo_matrix vs. sparse.COO来源

参考文献

用Keras训练稀疏的TensorFlow模型

如何在Tensorflow Keras中设计输入稀疏的深度学习模型?

稀疏矩阵的神经网络。

用scipy稀疏矩阵训练神经网络? 文档的 sparse 图书馆
0
投票

您可以简单地使用 np.reshape

https:/numpy.orgdoc1.18referencegeneratednumpy.reshape.html。

other_features_train = other_features_train.reshape(other_features_train.shape[0], other_features_train.shape[1], 1)

other_features_cv = other_features_cv.reshape(other_features_cv.shape[0], other_features_cv.shape[1], 1)

other_features_test = other_features_test.reshape(other_features_test.shape[0], other_features_test.shape[1], 1)

另外,你需要修改这一行

input_model_2 = Input(shape=(101, 1),name='other_features')

Conv1D期望的是三维数据,而不是二维数据。