プロジェクトアドレス
https://github.com/yao8839836/text_gcn
環境構成
Python 3.6
20ngの記事サンプル
差出人:[email protected](dean.kaflowitz)件名:Re:聖書のクイズの回答について組織:AT&T配布:na行:18記事healta.153.735242337 @ saturn.wwc.edu、healta @saturn。 wwc.edu(Tammy R Healy)は次のように書いています:>>>#12)2つのケリバムは契約の箱にあります。神が「偶像を作らない」と言われたとき、彼は崇拝されるために造られた偶像について言及していました。>契約の箱は破壊されておらず、大祭司だけが至聖所に入ることができました。>至聖所では、年に一度、贖罪の日に保管されていました。私は原語に精通していないか、知識がありませんが、「偶像」という言葉があり、翻訳者は原文に「偶像」と書かれていれば「偶像」の代わりに「偶像」という言葉を使用したと思います。ですから、ここではあなたが間違っていると思いますが、それでも私も間違っている可能性があります。私はあなたが提供する解釈が正しいかどうかを判断する方法を提案しているだけです。ディーン・カフロウィッツ
python remove_words.py 20ng
データセット= sys.argv [1]:20ngの
統計的単語頻度、
低頻度の単語と
ストップワードのフィルタリング、処理されたすべての記事の20ng.clean.txtへの書き込み( 'word1 word2word3…\ nword1word2…\ n…')
python build_graph.py 20ng
doc_train_list [0]:
doc_content_list [0]:
train_ids_str:
「idx1 \ nidx2 \ n…」
shuffle_doc_name_str(上記のトレーニング):
「name1 \ nname2 \ n…」
shuffle_doc_words_str
少し
word_doc_list *
{word1:[1,2,3,4]、word2:[2,3,4,5]、word3:[100,203、…]}
は、word1が最初の1、2、3、および4の記事に登場したことを示します
word_doc_freq
{word1:4、word2:4、...}
は、word1が4つの記事に登場したことを示します
word_id_map
{word1:0、word2:1、word3:2…}
vocab_str
label_set
label_list_str
バツ
row_x(real_train_size X
word_embeddings_dim):[0,0,0,0、... 0、1,1,1,1、... 1、2,2,2,2、... 2、...]
300 300 300
COL_X(real_train_size X word_embeddings_dim):
[0,1,2,3、… 299,0,1,2,3 、…299、…]
data_x(real_train_size x word_embeddings_dim)
x = sp.csr_matrix((data_x、(row_x、col_x))、 shape =(
real_train_size、word_embeddings_dim))
Y
[[0,1,0,0,0、…]、[1,0,0,0、…]、…]
tx
テストx
ty
テストy
allx(doc + word)
word_vectors:(vocab_size、word_embeddings_dim)
row_allx \ col_allx \ data_allxは上記と同じですが、すべてのトレーニング記事とすべての語彙が含まれている点が異なります。
もう一度一つの
row_allx:[0,0、…、1,1、…、train_size-1、train_size-1、…train_size + vocab_size-1、train_size + vocab_size-1、…]
味方
[[0,1,0,0,0、…]、[1,0,0,0、…]、…、[0,0,0,0、…]]
タグ付き記事|タグなしの単語
一時的な要約
print(x.shape、y.shape、tx.shape、ty.shape、allx.shape、ally.shape)
(10183、300)(10183、20)(7532、300)(7532、20)(54071、300)(54071、20)
ウィンドウズ
window_size = 20
[[w1、w2、w3、…w14]、[w1、w2、…w20]、…]
記事に14ワードしかない
場合は、ウィンドウに直接参加します。それ以外の場合、ウィンドウは次の記事に表示されます。1.の手順。上にスワイプします。つまり、length-lengthの記事はlength-window_size +1ウィンドウを生成できます
word_window_freq
{word1:freq1、word2:freq2、word3:freq3}
word1がfreq1のさまざまなウィンドウに表示されました
word_pair_count
{'1498,2066':3、 '2066,1498':3、...}
双方向グラフ、語彙の1498番目の単語と2066番目の単語がすべてのウィンドウに3回一緒に表示されます
ここでのカウントは上記のfreqという単語とは異なるように感じます
- word_window_freqの単語が出現したウィンドウの数を指す回数
- word_pair_countの単語グループが、すべてのウィンドウに表示されるペアの総数を指す回数。つまり、ウィンドウに複数のペアが存在する場合があります。
PMI(ワードワード)
単語のペアを考えてみましょう。word1は語彙のi番目、word2は語彙のj番目の
行です:
[train_size + i、…]
col
[train_size + j、…]
weight
[pmi_i_j]
他の場所について考えていますか?train_size x train_size inside?
doc_word_freq
{'doc_id1、word_id1':3、...}
は、doc_id1に対応する記事で、word_id1に対応する単語が3回出現することを示します。
TF-IDF(ドキュメントワード)
承接的的问题
行:
[train_size、train_size + i…train_size + vocab_size-1、| 0、1、2、…train_size-1、| train_size + vocab_size + i、…train_size + vocab_size + test_size]
adj = sp.csr_matrix(
(weight、(row、col))、shape =(node_size、node_size))
python train.py 20ng
load_corpus
- adj:まったくわかりません:adj = adj + adj.T.multiply(adj.T> adj)-adj.multiply(adj.T> adj)、元のadjは、adjの転置に対応する要素を追加しますは形容詞よりも大きい、形容詞が形容詞の転置よりも小さい対応する要素を差し引いたもの
- 機能:(train_size(doc)+ vocab_size + test_size)x 300
- y_train:(train_size(doc)+ vocab_size + test_size)x label_num、ただし[1,1,1(real_train_size)0,0,0 ...]の1にラベルがある場所のみ、その他はラベルなし
- y_val:[0,0,0(real_train_size)、1,1,1(val_size)、0,0,0…]
- y_test:[0,0,0(real_train_size)、0,0,0(val_size)、0,0,0(vocab_size)、1,1,1(test_size)]
- train_mask
- val_mask
- test_mask
- train_size
- test_size
features = sp.identity(features.shape [0])
次のコードは、例として入力features = sp.identity(3)を取ります。
import scipy.sparse as sp
import numpy as np
def preprocess_features(features):
(features)
(0, 0) 1.0
(1, 1) 1.0
(2, 2) 1.0
"""Row-normalize feature matrix and convert to tuple representation"""
rowsum = np.array(features.sum(1)) # 每一行的和
print("rowsum",rowsum)
(rowsum)
[[1.]
[1.]
[1.]]
r_inv = np.power(rowsum, -1).flatten() # 每一行的行的倒数,一行上所有元素乘上和的倒数,做的就是归一化
print("np.power(rowsum, -1)",np.power(rowsum, -1))
(r_inv)
[1. 1. 1.]
r_inv[np.isinf(r_inv)] = 0. # 把无穷大无穷小的值都变为0
r_mat_inv = sp.diags(r_inv) # 以每一行的和的倒数为对角元素,创建矩阵,用于与原来矩阵进行相乘
print("r_mat_inv",r_mat_inv)
(r_mat_inv)
(0, 0) 1.0
(1, 1) 1.0
(2, 2) 1.0
features = r_mat_inv.dot(features) # 矩阵乘法,做归一化
print("feature", features)
(features)
(0, 0) 1.0
(1, 1) 1.0
(2, 2) 1.0
return sparse_to_tuple(features)
def sparse_to_tuple(sparse_mx):
"""Convert sparse matrix to tuple representation."""
def to_tuple(mx):
if not sp.isspmatrix_coo(mx):
mx = mx.tocoo()
coords = np.vstack((mx.row, mx.col)).transpose()
values = mx.data
shape = mx.shape
return coords, values, shape # 列下标和行下标,对应的元素,矩阵大小
if isinstance(sparse_mx, list):
for i in range(len(sparse_mx)):
sparse_mx[i] = to_tuple(sparse_mx[i])
else:
sparse_mx = to_tuple(sparse_mx)
return sparse_mx
したがって、preprocess_features(features)は最終的に次を返します。
サポート= [preprocess_adj(adj)]
def normalize_adj(adj):
"""Symmetrically normalize adjacency matrix."""
adj = sp.coo_matrix(adj)
rowsum = np.array(adj.sum(1))
d_inv_sqrt = np.power(rowsum, -0.5).flatten()
d_inv_sqrt[np.isinf(d_inv_sqrt)] = 0.
d_mat_inv_sqrt = sp.diags(d_inv_sqrt)
return adj.dot(d_mat_inv_sqrt).transpose().dot(d_mat_inv_sqrt).tocoo()
def preprocess_adj(adj):
"""Preprocessing of adjacency matrix for simple GCN model and conversion to tuple representation."""
adj_normalized = normalize_adj(adj + sp.eye(adj.shape[0]))
return sparse_to_tuple(adj_normalized)
すべきことは、論文の内容です:(
詳細に読むために)
プレースホルダー
placeholders = {
'support': [tf.sparse_placeholder(tf.float32) for _ in range(num_supports)],
'features': tf.sparse_placeholder(tf.float32, shape=tf.constant(features[2], dtype=tf.int64)),
'labels': tf.placeholder(tf.float32, shape=(None, y_train.shape[1])),
'labels_mask': tf.placeholder(tf.int32),
'dropout': tf.placeholder_with_default(0., shape=()),
# helper variable for sparse dropout
'num_features_nonzero': tf.placeholder(tf.int32)
}
sparse_placeholderがここにフィードする必要があるデータは(インデックス、値、形状)であり、これはpreprocess_featuresによって返される3つのものです。
create_model
2層gcnネットワーク
self.layers.append(GraphConvolution)x 2
次に、静的グラフを作成して作成します。
for layer in self.layers:
hidden = layer(self.activations[-1])
self.activations.append(hidden)
self.outputs = self.activations[-1]
変数の保存:
variables = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope=self.name)
self.vars = {var.name: var for var in variables}
損失
# 为什么只需要第一层?
for var in self.layers[0].vars.values():
self.loss += FLAGS.weight_decay * tf.nn.l2_loss(var)
# 需要对有标签的进行计算
def masked_softmax_cross_entropy(preds, labels, mask):
"""Softmax cross-entropy loss with masking."""
print(preds)
loss = tf.nn.softmax_cross_entropy_with_logits(logits=preds, labels=labels)
mask = tf.cast(mask, dtype=tf.float32)
mask /= tf.reduce_mean(mask)
loss *= mask
return tf.reduce_mean(loss)
acc
opt_op
self.opt_op = self.optimizer.minimize(self.loss)
トレイン(計算プロセス)
まず、入力を最初のレイヤーに渡します。
self.layers.append(GraphConvolution(input_dim=self.input_dim,
output_dim=FLAGS.hidden1, # 200
placeholders=self.placeholders,
act=tf.nn.relu,
dropout=True,
featureless=True,
sparse_inputs=True,
logging=self.logging))
最初にドロップアウトを実行します(スパースドロップアウト)
# dropout
if self.sparse_inputs:
x = sparse_dropout(x, 1-self.dropout, self.num_features_nonzero)
else:
x = tf.nn.dropout(x, 1-self.dropout)
def sparse_dropout(x, keep_prob, noise_shape):
"""Dropout for sparse tensors."""
random_tensor = keep_prob # 保留的概率
random_tensor += tf.random_uniform(noise_shape) # 按照feature中有实质的个数,返回一个(个数,)的向量,每一个元素值是random_uniform出来的,然后加上keep_prob
dropout_mask = tf.cast(tf.floor(random_tensor), dtype=tf.bool) # 对于random_tensor中的值,如果>1,则为True,反之则为False
pre_out = tf.sparse_retain(x, dropout_mask) # 保留x中,dropout_mask对应位置是True的元素
return pre_out * (1./keep_prob) # 保留下来的元素再除以一个 小于1的概率?--->激活?
次に、畳み込みに進みます。最初の層の特徴のないものはTrueです。ここで奇妙なのは、特徴のないものの意味です。Trueの場合、計算は対称隣接行列と重みの乗算のみです。機能はありませんか?—最初の特徴は単位配列であり、計算に参加する必要がまったくないことを後で知りました...:
supports = list()
for i in range(len(self.support)):
if not self.featureless:
pre_sup = dot(x, self.vars['weights_' + str(i)],
sparse=self.sparse_inputs)
else:
pre_sup = self.vars['weights_' + str(i)]
support = dot(self.support[i], pre_sup, sparse=True)
supports.append(support)
output = tf.add_n(supports) # tf.add_n就是把supports列表中的所有support对应元素相加
def dot(x, y, sparse=False):
"""Wrapper for tf.matmul (sparse vs dense)."""
if sparse:
res = tf.sparse_tensor_dense_matmul(x, y)
else:
res = tf.matmul(x, y)
return res
バイアスと埋め込み、埋め込みは最初のレイヤーの出力であり、self.act(output)を次のレイヤーに渡す必要があることがわかります
# bias
if self.bias:
output += self.vars['bias']
self.embedding = output #output
return self.act(output)
次に、self.act(output)を2番目のレイヤーに渡します。
self.layers.append(GraphConvolution(input_dim=FLAGS.hidden1,
output_dim=self.output_dim,
placeholders=self.placeholders,
act=lambda x: x,
dropout=True,
logging=self.logging))
ここではfeatureless = Falseであることに注意してください。
#いくつかの奇妙なエラーの太字
AttributeError: module 'tensorflow' has no attribute 'random_uniform'
解決策:
https ://blog.csdn.net/weixin_43763859/article/details/104537392
Could not load dynamic library 'libcudart.so.11.0'; dlerror: libcudart.so.11
I tensorflow/stream_executor/cuda/cudart_stub.cc:29] Ignore above cudart dlerror if you do not have a GPU set up on your machine.
解決策(cudatoolkit = 11.0をダウンロード):
https ://blog.csdn.net/qq_28193019/article/details/103146116
Cannot use GPU when output.shape[1] * nnz(a) > 2^31
https://blog.csdn.net/weixin_35970195/article/details/112585490を解決します