将 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.sparse
和 numpy
数组。从稀疏矩阵转换为
非稀疏(密集)格式(这不是神经网络中的密集层),使用
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
PyTorch:torch.sparse
⭐
PyTorch 库还提供了使用 sparce 张量的方法。
文档 torch.sparse
:https://pytorch.org/docs/stable/sparse.html#sparse-coo-docs
参考资料
我想将 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
数组转换为 3Dnumpy
数组 - 使用稀疏和非稀疏(或密集)数组之间的来回转换
scipy.sparse.coo_matrix
用于二维numpy
数组sparse.COO
用于 3Dnumpy
数组
使用稀疏矩阵作为 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.sparse
和 numpy
数组。从稀疏矩阵转换为
非稀疏(密集)格式(这不是神经网络中的密集层),使用
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
PyTorch:torch.sparse
⭐
PyTorch 库还提供了使用 sparce 张量的方法。
文档
torch.sparse
:https://pytorch.org/docs/stable/sparse.html#sparse-coo-docs