質問編集履歴

1

解決

2020/01/02 11:19

投稿

hosihosieruhu
hosihosieruhu

スコア8

test CHANGED
File without changes
test CHANGED
@@ -1,741 +1 @@
1
1
  ChainerでRNNを使って自動文章生成したいのですが、TypeError: Can't broadcastという調べてもよくわからないエラーがでます。
2
-
3
-
4
-
5
- ソースは「Chainerで作るコンテンツ自動生成AIプログラミング入門」という本のコピペです。
6
-
7
-
8
-
9
- 環境はgoogle colabです。
10
-
11
-
12
-
13
- cudaとcupy、chainerのバージョンも合ってます
14
-
15
- プログラムは2つです
16
-
17
- 以下が用意したテキストファイルをRNNで学習させるプログラムchapt07-2.pyです。
18
-
19
- ちなみにテキストファイルは2万行の俳句です。
20
-
21
- ```
22
-
23
- import chainer
24
-
25
- import chainer.functions as F
26
-
27
- import chainer.links as L
28
-
29
- from chainer import training, datasets, iterators, optimizers
30
-
31
- from chainer.training import extensions
32
-
33
- import numpy as np
34
-
35
- import codecs
36
-
37
-
38
-
39
- batch_size = 10 # バッチサイズ10
40
-
41
- uses_device = 0 # GPU#0を使用
42
-
43
-
44
-
45
- # GPU使用時とCPU使用時でデータ形式が変わる
46
-
47
- if uses_device >= 0:
48
-
49
- import cupy as cp
50
-
51
- else:
52
-
53
- cp = np
54
-
55
-
56
-
57
- # RNNの定義をするクラス
58
-
59
- class Parses_Genarate_RNN(chainer.Chain):
60
-
61
-
62
-
63
- def __init__(self, n_words, nodes):
64
-
65
- super(Parses_Genarate_RNN, self).__init__()
66
-
67
- with self.init_scope():
68
-
69
- self.embed = L.EmbedID(n_words, n_words)
70
-
71
- self.l1 = L.LSTM(n_words, nodes)
72
-
73
- self.l2 = L.LSTM(nodes, nodes)
74
-
75
- self.l3 = L.Linear(nodes, n_words)
76
-
77
-
78
-
79
- def reset_state(self):
80
-
81
- self.l1.reset_state()
82
-
83
- self.l2.reset_state()
84
-
85
-
86
-
87
- def __call__(self, x):
88
-
89
- h0 = self.embed(x)
90
-
91
- h1 = self.l1(h0)
92
-
93
- h2 = self.l2(h1)
94
-
95
- y = self.l3(h2)
96
-
97
- return y
98
-
99
-
100
-
101
- # カスタムUpdaterのクラス
102
-
103
- class RNNUpdater(training.StandardUpdater):
104
-
105
-
106
-
107
- def __init__(self, train_iter, optimizer, device):
108
-
109
- super(RNNUpdater, self).__init__(
110
-
111
- train_iter,
112
-
113
- optimizer,
114
-
115
- device=device
116
-
117
- )
118
-
119
-
120
-
121
- def update_core(self):
122
-
123
- # 累積してゆく損失
124
-
125
- loss = 0
126
-
127
-
128
-
129
- # IteratorとOptimizerを取得
130
-
131
- train_iter = self.get_iterator('main')
132
-
133
- optimizer = self.get_optimizer('main')
134
-
135
- # ニューラルネットワークを取得
136
-
137
- model = optimizer.target
138
-
139
-
140
-
141
- # 文を一バッチ取得
142
-
143
- x = train_iter.__next__()
144
-
145
-
146
-
147
- # RNNのステータスをリセットする
148
-
149
- model.reset_state()
150
-
151
-
152
-
153
- # 分の長さだけ繰り返しRNNに学習
154
-
155
- for i in range(len(x[0])-1):
156
-
157
- # バッチ処理用の配列に
158
-
159
- batch = cp.array([s[i] for s in x], dtype=cp.int32)
160
-
161
- # 正解データ(次の文字)の配列
162
-
163
- t = cp.array([s[i+1] for s in x], dtype=cp.int32)
164
-
165
- # 全部が終端文字ならそれ以上学習する必要は無い
166
-
167
- if cp.min(batch) == 1 and cp.max(batch) == 1:
168
-
169
- break
170
-
171
- # 一つRNNを実行
172
-
173
- y = model(batch)
174
-
175
- # 結果との比較
176
-
177
- loss += F.softmax_cross_entropy(y, t)
178
-
179
-
180
-
181
- # 重みデータを一旦リセットする
182
-
183
- optimizer.target.cleargrads()
184
-
185
- # 誤差関数から逆伝播する
186
-
187
- loss.backward()
188
-
189
- # 新しい重みデータでアップデートする
190
-
191
- optimizer.update()
192
-
193
-
194
-
195
- # ファイルを読み込む
196
-
197
- s = codecs.open('all-sentences-parses.txt', 'r', 'utf8')
198
-
199
-
200
-
201
- # 全ての文
202
-
203
- sentence = []
204
-
205
-
206
-
207
- # 1行ずつ処理する
208
-
209
- line = s.readline()
210
-
211
- while line:
212
-
213
- # 一つの文
214
-
215
- one = [0] # 開始文字だけ
216
-
217
- # 行の中の単語を数字のリストにして追加
218
-
219
- one.extend(list(map(int,line.split(','))))
220
-
221
- # 行が終わったところで終端文字を入れる
222
-
223
- one.append(1)
224
-
225
- # 新しい文を追加
226
-
227
- sentence.append(one)
228
-
229
- line = s.readline()
230
-
231
- s.close()
232
-
233
-
234
-
235
- # 単語の種類
236
-
237
- n_word = max([max(l) for l in sentence]) + 1
238
-
239
-
240
-
241
- # 最長の文の長さ
242
-
243
- l_max = max([len(l) for l in sentence])
244
-
245
- # バッチ処理の都合で全て同じ長さに揃える必要がある
246
-
247
- for i in range(len(sentence)):
248
-
249
- # 足りない長さは終端文字で埋める
250
-
251
- sentence[i].extend([1]*(l_max-len(sentence[i])))
252
-
253
-
254
-
255
- # ニューラルネットワークの作成
256
-
257
- model = Parses_Genarate_RNN(n_word, 100)
258
-
259
-
260
-
261
- if uses_device >= 0:
262
-
263
- # GPUを使う
264
-
265
- chainer.cuda.get_device_from_id(0).use()
266
-
267
- chainer.cuda.check_cuda_available()
268
-
269
- # GPU用データ形式に変換
270
-
271
- model.to_gpu()
272
-
273
-
274
-
275
- # 誤差逆伝播法アルゴリズムを選択
276
-
277
- optimizer = optimizers.Adam()
278
-
279
- optimizer.setup(model)
280
-
281
-
282
-
283
- # Iteratorを作成
284
-
285
- train_iter = iterators.SerialIterator(sentence, batch_size, shuffle=False)
286
-
287
-
288
-
289
- # デバイスを選択してTrainerを作成する
290
-
291
- updater = RNNUpdater(train_iter, optimizer, device=uses_device)
292
-
293
- trainer = training.Trainer(updater, (100, 'epoch'), out="result")
294
-
295
- # 学習の進展を表示するようにする
296
-
297
- trainer.extend(extensions.ProgressBar(update_interval=1))
298
-
299
-
300
-
301
- # 機械学習を実行する
302
-
303
- trainer.run()
304
-
305
-
306
-
307
- # 学習結果を保存する
308
-
309
- chainer.serializers.save_hdf5( 'chapt07.hdf5', model )
310
-
311
- ```
312
-
313
-
314
-
315
- 以下が先ほど作成した学習結果を元に文章自動生成するプログラムchapt07-4.pyです。
316
-
317
- word2vecのモデルを使用ますが、これが壊れているという事は考えにくいです
318
-
319
-
320
-
321
- ```
322
-
323
- import torch
324
-
325
- import torchvision
326
-
327
- import torchvision.transforms as transforms
328
-
329
- from torch import nn, optim
330
-
331
- import torch.nn.functional as F
332
-
333
- from torch.utils.data import Dataset, DataLoader, TensorDataset
334
-
335
- import numpy as np
336
-
337
- import sys
338
-
339
- import codecs
340
-
341
- from gensim.models import word2vec
342
-
343
-
344
-
345
- trainset = torchvision.datasets.MNIST(root='./data',
346
-
347
- train=True,
348
-
349
- download=True,
350
-
351
- transform=transforms.ToTensor())
352
-
353
- trainloader = torch.utils.data.DataLoader(trainset,
354
-
355
- batch_size=batch_size,
356
-
357
- shuffle=True)
358
-
359
-
360
-
361
- testset = torchvision.datasets.MNIST(root='./data',
362
-
363
- train=False,
364
-
365
- download=True,
366
-
367
- transform=transforms.ToTensor())
368
-
369
- testloader = torch.utils.data.DataLoader(testset,
370
-
371
- batch_size=batch_size,
372
-
373
- shuffle=False)
374
-
375
-
376
-
377
-
378
-
379
- # GPU使用時とCPU使用時でデータ形式が変わる
380
-
381
- if uses_device >= 0:
382
-
383
- import cupy as cp
384
-
385
- import chainer.cuda
386
-
387
- else:
388
-
389
- cp = np
390
-
391
-
392
-
393
- sys.stdout = codecs.getwriter('utf_8')(sys.stdout)
394
-
395
-
396
-
397
- # RNNの定義をするクラス
398
-
399
- class Parses_Genarate_RNN(nn.Module):
400
-
401
-
402
-
403
- def __init__(self, n_words, nodes):
404
-
405
- super(Parses_Genarate_RNN, self).__init__()
406
-
407
- with self.init_scope():
408
-
409
- self.embed = L.EmbedID(n_words, n_words)
410
-
411
- self.l1 = L.LSTM(n_words, nodes)
412
-
413
- self.l2 = L.LSTM(nodes, nodes)
414
-
415
- self.l3 = L.Linear(nodes, n_words)
416
-
417
-
418
-
419
- def reset_state(self):
420
-
421
- self.l1.reset_state()
422
-
423
- self.l2.reset_state()
424
-
425
-
426
-
427
- def __call__(self, x):
428
-
429
- h0 = self.embed(x)
430
-
431
- h1 = self.l1(h0)
432
-
433
- h2 = self.l2(h1)
434
-
435
- y = self.l3(h2)
436
-
437
- return y
438
-
439
-
440
-
441
- # ファイルを読み込む
442
-
443
- w = codecs.open('all-words-parses.txt', 'r', 'utf8')
444
-
445
-
446
-
447
- # 単語の一覧
448
-
449
- words_parse = {}
450
-
451
-
452
-
453
- # 1行ずつ処理する
454
-
455
- line = w.readline()
456
-
457
- while line:
458
-
459
- # 行の中の単語をリストする
460
-
461
- l = line.split(',')
462
-
463
- if len(l) == 2:
464
-
465
- r = int(l[0].strip())
466
-
467
- if r in words_parse:
468
-
469
- words_parse[r].append(l[1].strip())
470
-
471
- else:
472
-
473
- words_parse[r] = [l[1].strip()]
474
-
475
- line = w.readline()
476
-
477
- w.close()
478
-
479
-
480
-
481
- # ニューラルネットワークの作成
482
-
483
- model = Parses_Genarate_RNN(max(words_parse.keys())+1, 20)
484
-
485
-
486
-
487
- # 学習結果を読み込む
488
-
489
- chainer.serializers.load_hdf5( 'chapt07.hdf5', model )
490
-
491
-
492
-
493
- if uses_device >= 0:
494
-
495
- # GPUを使う
496
-
497
- chainer.cuda.get_device_from_id(0).use()
498
-
499
- chainer.cuda.check_cuda_available()
500
-
501
- # GPU用データ形式に変換
502
-
503
- model.to_gpu()
504
-
505
-
506
-
507
- # 木探索で生成する最大の深さ
508
-
509
- words_max = 50
510
-
511
- # RNNの実行結果から検索する単語の数
512
-
513
- beam_w = 3
514
-
515
- # 生成した文のリスト
516
-
517
- parses = []
518
-
519
- # 木探索のスタック
520
-
521
- model_history = [model]
522
-
523
- # 現在生成中の文
524
-
525
- cur_parses = [0] # 開始文字
526
-
527
- # 現在生成中の文のスコア
528
-
529
- cur_score = []
530
-
531
- # 最大のスコア
532
-
533
- max_score = 0
534
-
535
-
536
-
537
- # 再帰関数の木探索
538
-
539
- def Tree_Traverse():
540
-
541
- global max_score
542
-
543
- # 現在の品詞を取得する
544
-
545
- cur_parse = cur_parses[-1]
546
-
547
- # 文のスコア
548
-
549
- score = np.prod(cur_score)
550
-
551
- # 現在の文の長さ
552
-
553
- deep = len(cur_parses)
554
-
555
- # 枝刈り - 単語数が5以上で最大スコアの6割以下なら、終わる
556
-
557
- if max_score > 0 and deep > 5 and max_score * 0.6 > score:
558
-
559
- return
560
-
561
- # 終了文字か、最大の文の長さ以上なら、品詞を追加して終わる
562
-
563
- if cur_parse == 1 or deep > words_max:
564
-
565
- # 文のデータをコピー
566
-
567
- data = np.array(cur_parses)
568
-
569
- # 文を追加
570
-
571
- parses.append((score, data))
572
-
573
- # 最大スコアを更新
574
-
575
- if max_score < score:
576
-
577
- max_score = score
578
-
579
- return
580
-
581
- # 現在のニューラルネットワークのステータスをコピーする
582
-
583
- cur_model = model_history[-1].copy()
584
-
585
- # 入力値を作る
586
-
587
- x = cp.array([cur_parse], dtype=cp.int32)
588
-
589
- # ニューラルネットワークに入力する
590
-
591
- y = cur_model(x)
592
-
593
- # 実行結果を正規化する
594
-
595
- z = F.softmax(y)
596
-
597
- # 結果のデータを取得
598
-
599
- result = z.data[0]
600
-
601
- if uses_device >= 0:
602
-
603
- result = chainer.cuda.to_cpu(result)
604
-
605
- # 結果を確立順に並べ替える
606
-
607
- p = np.argsort(result)[::-1]
608
-
609
- # 現在のニューラルネットワークのステータスを保存する
610
-
611
- model_history.append(cur_model)
612
-
613
- # 結果から上位のものを次の枝に回す
614
-
615
- for i in range(beam_w):
616
-
617
- # 現在生成中の文に一文字追加する
618
-
619
- cur_parses.append(p[i])
620
-
621
- # 現在生成中の文のスコアに一つ追加する
622
-
623
- cur_score.append(result[p[i]])
624
-
625
- # 再帰呼び出し
626
-
627
- Tree_Traverse()
628
-
629
- # 現在生成中の文を一つ戻す
630
-
631
- cur_parses.pop()
632
-
633
- # 現在生成中の文のスコアを一つ戻す
634
-
635
- cur_score.pop()
636
-
637
- # ニューラルネットワークのステータスを一つ戻す
638
-
639
- model_history.pop()
640
-
641
-
642
-
643
- # 木検索して文章を生成する
644
-
645
- Tree_Traverse()
646
-
647
-
648
-
649
- # Word2Vecのモデルを読み込む
650
-
651
- word_vec = word2vec.Word2Vec.load('word2vec.gensim.model')
652
-
653
-
654
-
655
- # 文章のターゲット
656
-
657
- target_str = ['元日']
658
-
659
- #target_str = ['神']
660
-
661
- #target_str = ['キリスト']
662
-
663
- #target_str = ['父','子','聖霊']
664
-
665
- #target_str = ['不思議','の','国','の','アリス']
666
-
667
- #target_str = ['三月','うさぎ','の','お茶','会']
668
-
669
- #target_str = ['女王']
670
-
671
-
672
-
673
- # 指定した品詞の単語を文章がターゲットに近づくように返す
674
-
675
- def similarity_word( parse, history ):
676
-
677
- scores = []
678
-
679
- # 品詞から候補をリスト
680
-
681
- for i in range(len(words_parse[parse])):
682
-
683
- w = words_parse[parse][i]
684
-
685
- if w in word_vec:
686
-
687
- # 候補のベクトルを履歴ベクトルに足す
688
-
689
- t = history[:]
690
-
691
- t.append(w)
692
-
693
- # ターゲットとの距離を計算
694
-
695
- sim = word_vec.n_similarity(target_str, t)
696
-
697
- scores.append((sim, w))
698
-
699
- # 結果をスコア順に並べ替える
700
-
701
- result = sorted(scores, key=lambda x: x[0])[::-1]
702
-
703
- return result[0]
704
-
705
-
706
-
707
-
708
-
709
- # スコアの高いものから順に表示する
710
-
711
- result_set = sorted(parses, key=lambda x: x[0])[::-1]
712
-
713
- # 10個または全部の少ない方の数だけ表示
714
-
715
- for i in range(min([10,len(result_set)])):
716
-
717
- # 結果を取得
718
-
719
- s, l = result_set[i]
720
-
721
- # これまで登場した単語
722
-
723
- history = []
724
-
725
- # 開始文字と終端文字を除いてループ
726
-
727
- for j in range(1,len(l)-1):
728
-
729
- score, cur_word = similarity_word(l[j], history)
730
-
731
- history.append(cur_word)
732
-
733
- sys.stdout.buffer.write(cur_word.encode('utf-8'))
734
-
735
-
736
-
737
- sys.stdout.buffer.write("\n".encode('utf-8'))
738
-
739
- sys.stdout.buffer.flush()
740
-
741
- ```