1 序列
数据除了在空间上可能出现关联性外,也可能在时间上,比如一段语音、一段文字:
所以面对这样在时间上有关联性的数据,神经网络该如何去识别和处理呢?
我们以文字举例,假如这是某个视频的评论:
在ASCII中,每一个字母都对应一个数字,而在自然语言中,我们一般把词作为自然语言处理的基本单位,那么如何把一个词转化为数字呢?
机制如你,会想到:查字典!
,我们以英文Nice to meet you
为例,我们先从字典表中找到Nice、to、meet、you这四个单词的索引值,然后把索引值转化为词向量送入到神经网络中。
中文也是这个思路,只不过不像是英文可以自然地通过空格来切割一个句子的单词。中文要麻烦一点,需要先分词
自然语言中会对词汇的表示方法做进一步的处理,机智如你会想到“One-Hot编码”
,但是呆板的Ont-Hot编码却无法体现猫和狗的相关性
、苹果和猫的无关性
等。
再者One-Hot编码会让输入的数据变大
,假如词典有一万个单词,四个词则输入数据就有4W个元素。
所以NLP中提出了“词向量”的概念,不过这与神经网络没多大关系
这里我们简单了解一下,语言本身就是对现实世界的描述
,词汇本就是用来指代一个事物的,比如狗
这个词,我们从多个角度来描述这个词,提取多个特征值
,形成一个词向量
:
为方便讲解,我们以两个特征维度
为例,在二维空间画出来,最后会是这样:
如此我们重新理一遍整个过程。以“这个视频非常精彩”
、“这个视频非常好看”
两句为例,首先对这两句分词统计
组成词向量嵌入矩阵(词汇表的词向量集合)
,然后点乘“这个、视频、非常、精彩”的One-Hot矩阵
,提取出它们各自的词向量,最后矩阵平铺
送入模型训练。
值得一提的是,我们把矩阵点乘这一层称为嵌入层
:
2 代码实现
一份网购评论数据:online_shopping_10_cats.csv
cat,label,review 书籍,1,做父母一定要有刘墉这样的心态,不断地学习,不断地进步,不断地给自己补充新鲜血液,让自己保持一颗年轻的心。我想,这是他能很好的和孩子沟通的一个重要因素。读刘墉的文章,总能让我看到一个快乐的平易近人的父亲,他始终站在和孩子同样的高度,给孩子创造着一个充满爱和自由的生活环境。很喜欢刘墉在字里行间流露出的做父母的那种小狡黠,让人总是忍俊不禁,父母和子女之间有时候也是一种战斗,武力争斗过于低级了,智力较量才更有趣味。所以,做父母的得加把劲了,老思想老观念注定会一败涂地,生命不息,学习不止。家庭教育,真的是乐在其中。 书籍,1,作者真有英国人严谨的风格,提出观点、进行论述论证,尽管本人对物理学了解不深,但是仍然能感受到真理的火花。整本书的结构颇有特点,从当时(本书写于八十年代)流行的计算机话题引入,再用数学、物理学、宇宙学做必要的铺垫——这些内容占据了大部分篇幅,最后回到关键问题:电脑能不能代替人脑。和现在流行的观点相反,作者认为人的某种“洞察”是不能被算法模拟的。也许作者想说,人的灵魂是无可取代的。 书籍,1,作者长篇大论借用详细报告数据处理工作和计算结果支持其新观点。为什么荷兰曾经县有欧洲最高的生产率?为什么在文化上有着深刻纽带关系的中国和日本却在经济发展上有着极大的差异?为什么英国的北美殖民地造就了经济强大的美国,而西班牙的北美殖民却造就了范后的墨西哥?……很有价值,但不包括【中国近代史专业】。 书籍,1,作者在战几时之前用了"拥抱"令人叫绝.日本如果没有战败,就有会有美军的占领,没胡官僚主义的延续,没有战后的民发反思,没有~,就不会让日本成为一个经济强国.当然,美国人也给日本人带来了耻辱.对日中关系也造成了深远的影响.文中揭露了"东京审判"中很多鲜为人知的东西.让人惊醒.唉!中国人民对日本的了解是不是太少了. 书籍,1,作者在少年时即喜阅读,能看出他精读了无数经典,因而他有一个庞大的内心世界。他的作品最难能可贵的有两点,一是他的理科知识不错,虽不能媲及罗素,但与理科知识很差的作家相比,他的文章可读性要强;其二是他人格和文风的朴实,不造作,不买弄,让人喜欢。读他的作品,犹如听一个好友和你谈心,常常唤起心中的强烈的共鸣。他的作品90年后的更好些。衷心祝愿周国平健康快乐,为世人写出更多好作品。 书籍,1,作者有一种专业的谨慎,若能有幸学习原版也许会更好,简体版的书中的印刷错误比较多,影响学者理解,全书结构简单,但内容详实,学起来如鱼得水非常轻松。这只是一项技术而已,若可以结合本专业,将会得到更高的学习快乐,家财万贯不如一技在身,一技在身不如一念在心,本书有不仅有技,而且有念。书中佳品。 ... 完整版在文末 每条数据有三个部分:商品分类、情感标签数据(1正面、0负面)、评论文本
数据操作工具:shopping_data.py
import os import keras import numpy as np import keras.preprocessing.text as text import re import jieba import random def load_data(): xs = [] ys = [] with open(os.path.dirname(os.path.abspath(__file__))+'/online_shopping_10_cats.csv','r',encoding='utf-8') as f: line=f.readline()#escape first line"label review" while line: line=f.readline() if not line: break contents = line.split(',') # if contents[0]=="书籍": # continue label = int(contents[1]) review = contents[2] if len(review)>20: continue xs.append(review) ys.append(label) xs = np.array(xs) ys = np.array(ys) #打乱数据集 indies = [i for i in range(len(xs))] random.seed(666) random.shuffle(indies) xs = xs[indies] ys = ys[indies] m = len(xs) cutpoint = int(m*4/5) x_train = xs[:cutpoint] y_train = ys[:cutpoint] x_test = xs[cutpoint:] y_test = ys[cutpoint:] print('总样本数量:%d' % (len(xs))) print('训练集数量:%d' % (len(x_train))) print('测试集数量:%d' % (len(x_test))) return x_train,y_train,x_test,y_test def createWordIndex(x_train,x_test): x_all = np.concatenate((x_train,x_test),axis=0) #建立词索引 tokenizer = text.Tokenizer() #create word index word_dic = {} voca = [] for sentence in x_all: # 去掉标点 sentence = re.sub("[\s+\.\!\/_,$%^*(+\"\']+|[+——!,。?、~@#¥%……&*()]+", "", sentence) # 结巴分词 cut = jieba.cut(sentence) #cut_list = [ i for i in cut ] for word in cut: if not (word in word_dic): word_dic[word]=0 else: word_dic[word] +=1 voca.append(word) word_dic = sorted(word_dic.items(), key = lambda kv:kv[1],reverse=True) voca = [v[0] for v in word_dic] tokenizer.fit_on_texts(voca) print("voca:"+str(len(voca))) return len(voca),tokenizer.word_index def word2Index(words,word_index): vecs = [] for sentence in words: # 去掉标点 sentence = re.sub("[\s+\.\!\/_,$%^*(+\"\']+|[+——!,。?、~@#¥%……&*()]+", "", sentence) # 结巴分词 cut = jieba.cut(sentence) #cut_list = [ i for i in cut ] index=[] for word in cut: if word in word_index: index.append(float(word_index[word])) # if len(index)>25: # index = index[0:25] vecs.append(np.array(index)) return np.array(vecs)
comments_recognizer.py
我们先来康一下数据样子:
import shopping_data x_train, y_train, x_test, y_test = shopping_data.load_data() # 打印数据集 print('x_train.shape:', x_train.shape) print('y_train.shape:', y_train.shape) print('x_test.shape:', x_test.shape) print('y_test.shape:', y_test.shape) print(x_train[0]) print(y_train[0]) 总样本数量:16595 训练集数量:13276 测试集数量:3319 x_train.shape: (13276,) y_train.shape: (13276,) x_test.shape: (3319,) y_test.shape: (3319,) 京东自营服务确实很好,以后会继续购买。
炼丹训练:
import shopping_data # 数据对齐 from keras.utils import pad_sequences from keras.models import Sequential from keras.layers import Dense, Embedding from keras.layers import Flatten x_train, y_train, x_test, y_test = shopping_data.load_data() # 打印数据集 # print('x_train.shape:', x_train.shape) # print('y_train.shape:', y_train.shape) # print('x_test.shape:', x_test.shape) # print('y_test.shape:', y_test.shape) # print(x_train[0]) # print(y_train[0]) vocalen, word_index = shopping_data.createWordIndex(x_train, x_test) # print(word_index) # print('词典总词数:', vocalen) # 转化为索引向量 x_train_index = shopping_data.word2Index(x_train, word_index) x_test_index = shopping_data.word2Index(x_test, word_index) # 每一句话的索引向量个数不一样,我们需要把序列按照maxlen对齐 maxlen = 25 x_train_index = pad_sequences(x_train_index, maxlen=maxlen) x_test_index = pad_sequences(x_test_index, maxlen=maxlen) # 神经网络模型 model = Sequential() model.add( Embedding( trainable=True, # 是否可训练:是否让这一层在训练的时候更新参数 input_dim=vocalen, # 输入维度 output_dim=300, # 输出维度 input_length=maxlen # 序列长度 ) ) model.add(Flatten()) # 数据平铺 # 三个隐藏层 model.add(Dense(256, activation='relu')) model.add(Dense(256, activation='relu')) model.add(Dense(256, activation='relu')) # 二分类问题,使用sigmoid激活函数 model.add(Dense(1, activation='sigmoid')) model.compile( loss='binary_crossentropy', # 适用于二分类问题的交叉熵代价函数 optimizer='adam', # adam是一种使用动量的自适应优化器,比普通的sgd优化器更快 metrics=['accuracy'] ) # 训练 model.fit(x_train_index, y_train, batch_size=512, epochs=200) score, acc = model.evaluate(x_test_index, y_test) # 评估 print('Test score:', score) print('Test accuracy:', acc)