将 2D 稀疏矩阵转换为 3D 矩阵

convert 2D sparse matrix to 3D matrix

我想将 2D 稀疏矩阵转换为 3D 矩阵,因为我需要将其作为 conv1d 层的输入,它需要 3D 张量。

这是 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) 

请建议如何操作。

您可以简单地使用 np.reshape

https://numpy.org/doc/1.18/reference/generated/numpy.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 需要 3-d 数据,而不是 2-d。

解决方案

此处的解决方案需要明确以下几个概念。我将解释这些概念 在以下部分中。

  • keras 期望的输入
  • 可以对您的 keras 模型进行哪些修改以允许稀疏输入矩阵
  • 将 2D numpy 数组转换为 3D numpy 数组
  • 使用稀疏和非稀疏(或密集)数组之间的来回转换
    • scipy.sparse.coo_matrix 用于二维 numpy 数组
    • sparse.COO 用于 3D numpy 数组

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

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

  • 另一种选择是通过 subclassing tf.keras.layers.Layer class。看到这篇文章,[2]

  • 看来 tensorflow.keras 现在允许使用稀疏权重进行模型训练。所以, 在某个地方它有能力处理稀疏性。您可能想浏览文档, [1]这方面。

向 numpy 数组添加新轴

您可以使用 np.newaxis 将另一个轴添加到 numpy 数组,如下所示。

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: 一个 table 三列
    • 非零值

Scipy 稀疏矩阵需要 2D 输入矩阵

但是scipy.sparse以上三种稀疏矩阵的实现,只 将二维非稀疏矩阵视为输入。

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 throw an !!! ERROR !!!
coo_a3D = coo_matrix(coo_a2D.todense()[:,:,np.newaxis])

来自 3D 非稀疏输入矩阵的稀疏矩阵

是的,您可以使用 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

Source

PyTorch:torch.sparse

PyTorch 库还提供了使用 sparce 张量的方法。

参考资料

  1. Train sparse TensorFlow models with Keras

  2. How to design deep learning models with sparse inputs in Tensorflow Keras

  3. Neural network for sparse matrices

  4. Training Neural network with scipy sparse matrix?

  5. Documentation of sparse library