专栏首页杨熹的专栏中文NLP笔记:11. 基于 LSTM 生成古诗

中文NLP笔记:11. 基于 LSTM 生成古诗

基于 LSTM 生成古诗

1. 语料准备

  一共四万多首古诗,一行一首诗

2. 预处理

  将汉字表示为 One-Hot 的形式

  在每行末尾加上 ] 符号是为了标识这首诗已经结束,说明 ] 符号之前的语句和之后的语句是没有关联关系的,后面会舍弃掉包含 ] 符号的训练数据。

      puncs = [']', '[', '(', ')', '{', '}', ':', '《', '》']

    def preprocess_file(Config):

        # 语料文本内容

        files_content = ''

        with open(Config.poetry_file, 'r', encoding='utf-8') as f:

            for line in f:

                # 每行的末尾加上"]"符号代表一首诗结束

                for char in puncs:

                    line = line.replace(char, "")

                files_content += line.strip() + "]"

        words = sorted(list(files_content))

        words.remove(']')

        counted_words = {}

        for word in words:

            if word in counted_words:

                counted_words[word] += 1

            else:

                counted_words[word] = 1

        # 去掉低频的字

        erase = []

        for key in counted_words:

            if counted_words[key] <= 2:

                erase.append(key)

        for key in erase:

            del counted_words[key]

        del counted_words[']']

        wordPairs = sorted(counted_words.items(), key=lambda x: -x[1])

        words, _ = zip(*wordPairs)

        # word到id的映射

        word2num = dict((c, i + 1) for i, c in enumerate(words))

        num2word = dict((i, c) for i, c in enumerate(words))

        word2numF = lambda x: word2num.get(x, 0)

        return word2numF, num2word, words, files_content

3. 模型参数配置

  class Config(object):

    poetry_file = 'poetry.txt'

    weight_file = 'poetry_model.h5'

    # 根据前六个字预测第七个字

    max_len = 6

    batch_size = 512

    learning_rate = 0.001

4. 构建模型

  通过 PoetryModel 类实现

      class PoetryModel(object):

        def __init__(self, config):

            pass

        def build_model(self):

            pass

        def sample(self, preds, temperature=1.0):

            pass

        def generate_sample_result(self, epoch, logs):

            pass

        def predict(self, text):

            pass

        def data_generator(self):

            pass

        def train(self):

            pass

  (1)init 函数

  加载 Config 配置信息,进行语料预处理和模型加载

      def __init__(self, config):

            self.model = None

            self.do_train = True

            self.loaded_model = False

            self.config = config

            # 文件预处理

            self.word2numF, self.num2word, self.words, self.files_content = preprocess_file(self.config)

            if os.path.exists(self.config.weight_file):

                self.model = load_model(self.config.weight_file)

                self.model.summary()

            else:

                self.train()

            self.do_train = False

            self.loaded_model = True

  (2)build_model 函数

  GRU 模型建立

      def build_model(self):

            '''建立模型'''

            input_tensor = Input(shape=(self.config.max_len,))

            embedd = Embedding(len(self.num2word)+1, 300, input_length=self.config.max_len)(input_tensor)

            lstm = Bidirectional(GRU(128, return_sequences=True))(embedd)

            dropout = Dropout(0.6)(lstm)

            lstm = Bidirectional(GRU(128, return_sequences=True))(embedd)

            dropout = Dropout(0.6)(lstm)

            flatten = Flatten()(lstm)

            dense = Dense(len(self.words), activation='softmax')(flatten)

            self.model = Model(inputs=input_tensor, outputs=dense)

            optimizer = Adam(lr=self.config.learning_rate)

            self.model.compile(loss='categorical_crossentropy', optimizer=optimizer, metrics=['accuracy'])

  (3)sample 函数

      def sample(self, preds, temperature=1.0):

        preds = np.asarray(preds).astype('float64')

        preds = np.log(preds) / temperature

        exp_preds = np.exp(preds)

        preds = exp_preds / np.sum(exp_preds)

        probas = np.random.multinomial(1, preds, 1)

        return np.argmax(probas)

  (4)训练模型

      def generate_sample_result(self, epoch, logs): 

            print("\n==================Epoch {}=====================".format(epoch))

            for diversity in [0.5, 1.0, 1.5]:

                print("------------Diversity {}--------------".format(diversity))

                start_index = random.randint(0, len(self.files_content) - self.config.max_len - 1)

                generated = ''

                sentence = self.files_content[start_index: start_index + self.config.max_len]

                generated += sentence

                for i in range(20):

                    x_pred = np.zeros((1, self.config.max_len))

                    for t, char in enumerate(sentence[-6:]):

                        x_pred[0, t] = self.word2numF(char)

                    preds = self.model.predict(x_pred, verbose=0)[0]

                    next_index = self.sample(preds, diversity)

                    next_char = self.num2word[next_index]

                    generated += next_char

                    sentence = sentence + next_char

                print(sentence)

  (5)predict 函数

  根据给出的文字,生成诗句

      def predict(self, text):

            if not self.loaded_model:

                return

            with open(self.config.poetry_file, 'r', encoding='utf-8') as f:

                file_list = f.readlines()

            random_line = random.choice(file_list)

            # 如果给的text不到四个字,则随机补全

            if not text or len(text) != 4:

                for _ in range(4 - len(text)):

                    random_str_index = random.randrange(0, len(self.words))

                    text += self.num2word.get(random_str_index) if self.num2word.get(random_str_index) not in [',', '。',

                                                                                                              ','] else self.num2word.get(

                        random_str_index + 1)

            seed = random_line[-(self.config.max_len):-1]

            res = ''

            seed = 'c' + seed

            for c in text:

                seed = seed[1:] + c

                for j in range(5):

                    x_pred = np.zeros((1, self.config.max_len))

                    for t, char in enumerate(seed):

                        x_pred[0, t] = self.word2numF(char)

                    preds = self.model.predict(x_pred, verbose=0)[0]

                    next_index = self.sample(preds, 1.0)

                    next_char = self.num2word[next_index]

                    seed = seed[1:] + next_char

                res += seed

            return res

  (6) data_generator 函数

  生成数据,提供给模型训练时使用

        def data_generator(self):

            i = 0

            while 1:

                x = self.files_content[i: i + self.config.max_len]

                y = self.files_content[i + self.config.max_len]

                puncs = [']', '[', '(', ')', '{', '}', ':', '《', '》', ':']

                if len([i for i in puncs if i in x]) != 0:

                    i += 1

                    continue

                if len([i for i in puncs if i in y]) != 0:

                    i += 1

                    continue

                y_vec = np.zeros(

                    shape=(1, len(self.words)),

                    dtype=np.bool

                )

                y_vec[0, self.word2numF(y)] = 1.0

                x_vec = np.zeros(

                    shape=(1, self.config.max_len),

                    dtype=np.int32

                )

                for t, char in enumerate(x):

                    x_vec[0, t] = self.word2numF(char)

                yield x_vec, y_vec

                i += 1

  (7)train 函数

      def train(self):

            #number_of_epoch = len(self.files_content) // self.config.batch_size

            number_of_epoch = 10

            if not self.model:

                self.build_model()

            self.model.summary()

            self.model.fit_generator(

                generator=self.data_generator(),

                verbose=True,

                steps_per_epoch=self.config.batch_size,

                epochs=number_of_epoch,

                callbacks=[

                    keras.callbacks.ModelCheckpoint(self.config.weight_file, save_weights_only=False),

                    LambdaCallback(on_epoch_end=self.generate_sample_result)

                ]

            )

5. 进行模型训练

  model = PoetryModel(Config)

6. 作诗

      text = input("text:")

    sentence = model.predict(text)

    print(sentence)


学习资料:

《中文自然语言处理入门实战》

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • DQN 的代码实现

    算法来自:Volodymyr Mnih,Playing Atari with Deep Reinforcement Learning

    杨熹
  • 用 RNN 训练语言模型生成文本

    ---- 本文结构: 什么是 Language Model? 怎么实现?怎么应用? ---- cs224d Day 8: 项目2-用 RNN 建立 Langua...

    杨熹
  • LEETCODE - Linked List 题目思路汇总

    浏览了一下 Leetcode 上 Linked List 的题目,我把它分为 6 类: 调换顺序 删除 合并 环 变身 复制 做Leetcode还是要归类总结才...

    杨熹
  • AlphaGo Zero你也来造一只,PyTorch实现五脏俱全| 附代码

    遥想当年,AlphaGo的Master版本,在完胜柯洁九段之后不久,就被后辈AlphaGo Zero (简称狗零) 击溃了。

    量子位
  • 【实战小项目】python开发自动化运维工具--批量操作主机

    有很多开源自动化运维工具都很好用如ansible/salt stack等,完全不用重复造轮子。只不过,很多运维同学学习Python之后,苦于没小项目训练,本篇演...

    用户1432189
  • 手把手教你用Python开发“剪刀石头布”小游戏【附源码】

    最近在学习PyQt5可视化界面,这是一个内容非常丰富的gui库,相对于tkinter库,功能更加强大,界面更加美观,操作也不难。于是我开始小试牛刀,用PyQt...

    python学习教程
  • 机器学习|用Q-Learning走迷宫

    上文中我们了解了Q-Learning算法的思想,基于这种思想我们可以实现很多有趣的功能和小demo,本文让我们通过Q-Learning算法来实现用计算机来走迷宫...

    数据山谷
  • 用 Python 写个坦克大战

    坦克大战是一款策略类的平面射击游戏,于 1985 年由 Namco 游戏公司发布,尽管时至今日已经有了很多衍生类的游戏,但这款游戏仍然受到了相当一部分人的欢迎,...

    纯洁的微笑
  • html5点击出现燃放烟花特效

    今天我发现了一个非常好的html特效,是由HTML5来实现的,效果非常绚丽。效果如下:

    无邪Z
  • 生成对抗网络(GAN)系列:WGAN与金融时序(附代码)

    过拟合是我们试图将机器学习技术应用于时间序列时遇到的问题之一。出现这个问题是因为我们使用我们所知道的唯一时间序列路径来训练我们的模型:已实现的历史。

    量化投资与机器学习微信公众号

扫码关注云+社区

领取腾讯云代金券