人工智能

应用机器学习和深度学习

深度葡萄酒设计师

这是另一篇来自埃文斯的文章,他给我们带来了深度啤酒设计师,今天回来聊聊酒!这是一篇比平时更长的文章,但包含了关于文本深度学习的有用信息。如果您正在寻找一个独特的文本示例,这就是为您准备的!

下面是我上一篇关于如何用MATLAB选择的博客文章完美的啤酒在美国,我决定探索一下我能把深度学习和葡萄酒结合起来做什么。
与啤酒类似,葡萄酒的选择种类繁多。在我选择葡萄酒之前,我需要弄清楚我真正喜欢的葡萄品种。 MATLAB能帮到我吗?如果我向MATLAB描述我的完美葡萄酒,它能帮我选择一款吗?不同葡萄酒品种的特点是什么?
有两种常见的方法来解决这样的文本分类问题:
  1. 训练长短期记忆(LSTM)网络,将文本数据视为时间序列,并学习时间步长之间的长期依赖关系。
  2. 训练卷积神经网络(CNN),将文本数据视为高光谱图像,并通过应用滑动卷积滤波器学习局部特征。
在这篇博文中,我将重点介绍第二种方法:通过将葡萄酒葡萄品种转换为图像并使用CNN对其进行分类。

背景:词嵌入

为了将文本转换为高光谱图像,我们可以使用单词嵌入,将单词序列映射到表示图像的2-D数组。换句话说,单词嵌入将单词映射到高维向量。这些向量有时具有有趣的性质。例如,给定意大利、罗马、巴黎和法国对应的单词向量,你可能会发现它们之间的关系:

意大利-罗马+巴黎≈法国

也就是说,对应于单词的向量意大利没有单词的组成部分罗马但是加入了这个词的成分巴黎近似等于对应的向量法国
要在MATLAB中做到这一点,我们可以使用文本分析工具箱™模型fastText英语160亿令牌词嵌入支持包。这个词嵌入将大约1,000,000个英语单词映射到1 × 300的向量。让我们使用fasttextwordem寝食函数加载单词嵌入。
emb = fasttextwordem寝料;
让我们想象向量这个词意大利,罗马,巴黎,法国.通过计算字向量使用word2vec函数,我们可以看到关系:
意大利= word2vec(emb,“意大利”);罗马= word2vec(emb,“罗马”);巴黎= word2vec(emb,“巴黎”);Word = vec2word(emb,意大利-罗马+巴黎)
字= "法国"

从文字到图像

要使用单词嵌入将单词序列映射到图像,让我们使用将文本分割为单词tokenizedDocument然后把这些词转换成一个序列向量doc2sequence
str = "西班牙的雨主要落在平原上。";文档= tokenizedDocument(str);序列= doc2sequence(emb,文档);
让我们来看看与这个单词序列对应的高光谱图像。
图I =序列{1};imagesc(I,[-1 1]) colorbar xlabel(“单词索引”)ylabel(“嵌入特征”)title(“单词向量”)
由此产生的图像并不是特别令人兴奋。它是一个C-by-S数组,其中C是单词嵌入的特征数(嵌入维度),S是文本中的单词数(序列长度)。当格式化为带有C通道的1 × n高光谱图像时,您可以将此数据输入CNN并应用高度为1的滑动滤波器。这些被称为一维卷积。

Load Wine评论数据

让我们下载葡萄酒评论并将数据提取到一个名为wine-reviews的文件夹中。下载数据后,可以使用winemag-data-130k-v2.csv将数据读取到一个表中readtable函数。数据包含特殊字符,例如Rosé中的é,因此我们也必须指定文本编码选项。
Filename = fullfile("wine-reviews","winemag-data-130k-v2.csv");data = readtable(文件名,"Encoding","UTF-8");数据。Variety = categorical(data.variety);

探索葡萄酒评论数据

为了感受数据,让我们使用单词云来可视化文本数据。首先创建不同葡萄品种的单词云。
图;wordcloud (data.variety);标题(“葡萄品种”)
为了快速验证文本分类是否可行,让我们快速为选定的类创建单词云,并检查它们之间的差异。如果您安装了文本分析工具箱,那么wordcloud功能将自动预处理字符串输入。为了更好地可视化,让我们从文本中删除一个常用词和葡萄品种列表。
标签= ["Gewürztraminer" "霞多丽" "内比欧罗" "马尔贝克"];commonWords = ["wine" "Drink" "Drink" " flavour " "finish" "palate" "notes" "aromas"];图为I = 1:4 subplot(2,2, I) label = labels(I);Idx = data。品种==标签;STR = data.description(idx);documents = tokenizedDocument(str) documents = removeWords(documents,commonWords);documents = removeWords(文档,标签);str = joinWords(文档);wordcloud (str); title(label) end
单词云显示,单词在不同葡萄品种中的分布是不同的。尽管像“水果”和“浆果”这样的词通常用来描述这些葡萄品种,但词云显示每种葡萄品种的词分布是不同的。
这表明在文本数据上训练分类器是有根据的。太好了!

为深度学习准备文本数据

为了使用卷积对文本数据进行分类,我们需要将文本数据转换为图像。为此,让我们填充或截断观察值,使其长度为常数S,并使用预训练的词嵌入将文档转换为长度为C的词向量序列。然后,我们可以将文档表示为1 × S × C图像(高1、宽S、通道C的图像)。
为了将文本数据从CSV文件转换为图像,我在这篇文章的最后有一个助手函数称为transformTextData.它创建一个tabularTextDatastore对象,并使用transform函数和一个自定义转换函数,将从tabularTextDatastore对象读取的数据转换为用于深度学习的图像。
在这个例子中,我们将用不同宽度的1-D卷积滤波器训练一个网络。每个过滤器的宽度对应于过滤器可以看到的单词数(n-gram长度)。该网络有多个卷积层分支,因此它可以使用不同的n-gram长度。

清理数据

删除没有标签的评论。
idxMissing = ismissing(data.variety);data(idxMissing,:) = [];
删除所有葡萄品种不在数据前200名中的评论。(如果你在前200个可供选择的葡萄酒中找不到你喜欢的葡萄酒,MATLAB可能帮不了你。)
numClasses = 200;[classCounts,classNames] = histcounts(data.variety);[~,idx] = maxk(classCounts,numClasses);classNames = classNames(idx);idx = ismember(data.variety,classNames);数据=数据(idx,:);
从数据中删除未使用的类别。
数据。变量= removecats(data.variety);classNames =类别(data.variety);

对数据进行分区

为了帮助评估网络的性能,让我们将数据划分为训练集、测试集和验证集。让我们留出30%的数据用于验证和测试(分成两个15%的分区)。
cvp = cvpartition(data.variety,'HoldOut',0.3);fileametrain = fullfile("wine-reviews","wineReviews_" + numClasses + "_classes_Train.csv");dataTrain = data(training(cvp),:);writetable (dataTrain filenameTrain,“编码”,“utf - 8”);dataHeldOut = data(test(cvp),:);cvp = cvpartition(dataHeldOut.variety,'HoldOut',0.5);filenameValidation = fullfile("wine-reviews","wineReviews_" + numClasses + "_classes_Validation.csv");dataValidation = dataHeldOut(training(cvp),:);writetable (dataValidation filenameValidation,“编码”,“utf - 8”);filenameTest = fullfile("wine-reviews","wineReviews_" + numClasses + "_classes_Test.csv"); dataTest = dataHeldOut(test(cvp),:); writetable(dataTest,filenameTest,"Encoding","UTF-8"); 需要从阅读代码中休息一下吗?阅读研究人员如何使用MATLAB制作更好的啤酒和葡萄酒这篇文章
从表中引入描述和多样性字段。
miniBatchSize = 128;ttdsTrain = tabularTextDatastore(fileametrain,…'SelectedVariableNames',["description" "variety"],…ReadSize, miniBatchSize);

指定输入大小

为了将文本数据输入到网络中,我们需要通过填充或截断序列将文本转换为固定大小的图像。理想情况下,我们需要选择一个值,使添加到序列的填充量和由于截断而丢弃的数据量最小化。让我们试着通过计算空格数和在直方图中绘制序列长度来估算每次评论的字数。
大多数评论的字数不超过80字。让我们在自定义变换函数中指定80,以此作为序列长度。transformTextData函数从tabularTextDatastore对象中读取数据,并返回一个包含预测器和响应的表。
sequenceLength = 80;tdsTrain = transform(ttdsTrain, @(data) transformTextData(data,sequenceLength,emb,classNames));
预测器是1-by-S- C数组,其中S是序列长度,C是特征的数量。这些回答就是分类标签。
预览(tdsTrain)
对于验证,让我们使用相同的步骤创建一个包含验证数据的转换数据存储。
ttdsValidation = tabularTextDatastore(filenameValidation,…'SelectedVariableNames',["description" "variety"],…ReadSize, miniBatchSize);tdsValidation = transform(ttdsValidation, @(data) transformTextData(data,sequenceLength,emb,classNames))

定义网络架构

现在让我们定义分类任务的网络架构,我们可以使用deepNetworkDesigner来创建网络。
组网结构介绍如下:
  • 输入大小为1 × S × C,其中S是序列长度,C是特征的数量(嵌入维度)。
  • 对于长度为1到5的n-gram,让我们创建包含卷积层、批处理规范化层、ReLU层、dropout层和最大池化层的层块。
  • 对于每个块,让我们指定256个大小为1 × N的卷积滤波器和大小为1 × s的池化区域,其中N是N -gram的长度。
  • 让我们将输入层连接到每个块,并使用深度连接层连接块的输出。
  • 最后,为了对输出进行分类,让我们包括一个输出大小为K的全连接层、一个softmax层和一个分类层,其中K是类的数量。

指定培训项目

numIterationsPerEpoch = floor(numObservationsTrain/miniBatchSize);选项= trainingOptions('adam',…“MaxEpochs”,50岁,…“洗牌”,“从来没有”,…MiniBatchSize, MiniBatchSize,……ValidationData, tdsValidation,……ValidationFrequency, numIterationsPerEpoch,……“阴谋”、“训练进步”,…“详细”,假);

列车网络的

最后,我们可以训练网络了!让我们用trainNetwork函数。根据硬件的不同,这可能需要很长时间。如果您在硬件或培训方面遇到麻烦,您可以通过电子邮件向Johanna索要一份经过培训的网络副本。
解百纳= trainNetwork(tdsTrain,lgraph,options);保存(“caberNet.mat”、“赤霞珠”)
*约翰娜致约安注:我在这个博客上有一个没有双关语的政策,“解百纳”是一个边界,所以把这当作一个警告。
在这里我们可以看到,训练准确率收敛到约93%,验证准确率收敛到约63%。这表明网络可能过度拟合训练数据。特别是,它可能是学习训练数据的特征,不能很好地推广到验证数据。这里需要更多的调查!

测试网络

现在网络已经训练好了,我们可以使用保留的测试数据来测试它。首先,让我们创建一个转换后的数据存储,其中包含保留的测试数据。
ttdsTest = tabularTextDatastore(filenameTest,…'SelectedVariableNames',["description" "variety"],…ReadSize, miniBatchSize);tdsTest = transform(ttdsTest, @(数据)transformTextData(数据,sequenceLength,emb,classNames));tbl = readall(ttdsTest);labelsTest = tbl.variety;YTest = categorical(labelsTest,classNames);YPred = category(赤霞珠,tdsTest,'MiniBatchSize', MiniBatchSize);
准确度= 0.6397
在这里,我们可以看到网络在保留测试数据上的准确率约为64%。鉴于品酒笔记的多样性和主观性,我认为这是一个不错的分数!

对新数据进行预测

下一步是在现实世界中尝试这个分类器!以下是我最近参加的一次品酒会的一些记录。
  • “一种爽脆的、金黄色的、有气泡的葡萄酒。散发着柑橘类水果和成熟核果的香气。在调色板上,充满活力的苹果和奶油质感。”
  • “稻草色中略带绿色。桃子和油桃的味道。浓郁微甜,浓郁的荔枝味。强烈的矿物味,带点甜味。”
  • “酒体呈淡麦秆色,带有浓郁的柑橘香味。口感上有强烈的醋栗和清脆的酸橙味道,并带有淡淡的橡木味。”
  • “深金色。浓郁的吐司和黄油香味,并带有浓郁的橡木味。口感上有浓郁的熟香蕉和熟苹果的味道。”
  • “酒体清淡,色泽苍白。草莓和森林水果的芳香。略带橡木味,单宁轻微。充满活力的红樱桃味道。”
  • 酒体中等,呈砖红色。散发着黑樱桃和紫罗兰的香气。复杂的味道,包括强烈的单宁以及黑色水果和胡椒的味道。”
  • “深宝石红色。带有黑樱桃、橡木和丁香的芳香。略带烟熏味,带有强烈的黑莓和甘草的味道。”
  • “强烈的黑洋流和蓝莓的香气。非常大的酒,酒精含量很高。口感浓郁,回味悠长。充满活力的黑色水果和香料的味道。”
为了使用网络使用这些笔记进行预测,我们需要使用与训练过程相同的步骤将文本转换为序列。通过使用text2sequence函数,我们可以将一个字符串数组转换为一个指定长度的字向量序列表。
sequencesNew = text2sequence(emb,str,sequenceLength);[YNewPred,scoresNew] = category (caberNet,sequencesNew);TBL =表;资源描述。PredictedVariety = YNewPred;资源描述。真正的多样性= YNewTest
在这里,网络正确地分类了8个中的4个。虽然我很想说卡瓦是一种闪闪发光的混合酒(严格来说,网络是正确的)。同样,说西拉而不是设拉子是可以原谅的,因为它们是不同名字下的同一品种。
假设8个中的6个……太棒了!

可视化网络预测

对于图像分类问题,您可以通过取一张图像,删除图像的一小块,测量分类是否变得更好或更差,然后将结果覆盖在图像上来可视化网络的预测。换句话说,如果删除了图像的一个补丁,分类变得更差,那么这个补丁必须包含属于真实类的特征。类似地,如果删除图像的一个补丁,分类变得更好,那么该补丁必须包含属于不同类别的特征,从而使分类器混淆。
我们可以用occlusionSensitivity函数。让我们从网络预测正确标签的文本数据中选择一个观察结果。
idxObservation = 2;strNew = str(idxObservation) labelTest = YNewTest(idxObservation)
strNew = "略带稻草色,略带绿色。桃子和油桃的味道。浓郁微甜,浓郁的荔枝味。回味柔和,带点甜味。”
labelTest = "Gewürztraminer"
让我们使用函数查看遮挡灵敏度分数plotOcclusion,我已经在博客文章的末尾列出了。这显示了哪些词块对预测的贡献最大。
H =数字;h.位置(3)= 1.5 * h.位置(3);plotOcclusion(赤霞珠、emb strNew、sequenceLength labelTest)
在这里,我们可以看到网络已经了解到短语“丰富和微甜”和“荔枝的味道”是Gewürztraminer品种的强烈指示,同样,短语“稻草色”和“桃子的味道”是这个品种的特征。
现在,让我们用同样的技术来想象一个错误分类的品种。
idxObservation = 8;strNew = str(idxObservation) labelTest = YNewTest(idxObservation)
strNew = "浓郁的黑樱桃香气。酒精度高,口感强烈。口感丰富,单宁浓郁,回味悠长。充满活力的樱桃味和淡淡的胡椒味。”
labelTest = "仙粉黛"
H =数字;h.位置(3)= 1.5 * h.位置(3);h.位置(4)= 1.5 * h.位置(4);plotOcclusion(赤霞珠、emb strNew、sequenceLength labelTest)
在这里,我们可以看到,除了“酒精含量高”,网络将许多短语理解为梅洛品种的强烈迹象。类似地,第二个图表显示,网络只理解文本中的一些短语是仙粉黛品种的特征,然而,短语“强烈的单宁”和包含“樱桃”或“樱桃”的短语相比之下特别不具有特征。
完美!现在我可以用MATLAB来帮助我识别我喜欢的葡萄酒。此外,我可以想象网络做出的预测,也许我自己也能学到更多的东西。我想我最好在更多的品酒会上测试一下这个网络……
所有的辅助函数都可以使用下面的MATLAB代码链接找到。
感谢Ieuan的这篇内容丰富的文章。他最初想把这篇文章命名为“数学的葡萄”,但我在博客上实施了不含双关语的政策。我特别喜欢他通过参加品酒会来实地测试他的代码,这就是奉献!有问题要问伊安吗?请在下方评论。

版权所有2018 The MathWorks, Inc.获取MATLAB代码

|
  • 打印
  • 发送电子邮件

评论

如欲留言,请点击在这里登录您的MathWorks帐户或创建一个新帐户。

Baidu
map