TensorFlow 实战(五)(1)

本文涉及的产品
文档翻译,文档翻译 1千页
文本翻译,文本翻译 100万字符
图片翻译,图片翻译 100张
简介: TensorFlow 实战(五)

第三部分:针对复杂问题的高级深度网络

自从卷积神经网络、LSTM 等模型问世以来,深度学习已经取得了长足的进展。亿级参数的 Transformer 模型在各方面表现都优于前面提到的模型。由于对更好的模型和快速开发机器学习模型的需求,跟踪和生产化机器学习模型是另一个备受关注的话题。

在第三部分中,我们首先讨论基于 RNN 的模型的一种更复杂的变体——序列到序列模型。然后我们将更详细地讨论基于 Transformer 的模型,并亲身感受它们在垃圾邮件分类和问答等任务中的运用。您还将学习如何利用像 Hugging Face 的 Transformers 这样的高级库快速实现解决方案。

接下来,您将学习如何使用 TensorBoard 跟踪模型的性能。您将学习如何轻松地在时间轴上可视化模型性能,以及性能分析等高级功能。最后,我们将介绍 TFX,这是一个标准化机器学习模型生产化的库。您将开发一个端到端管道,从数据到部署全面管理机器学习工作流程。

第十一章:序列到序列学习:第一部分

本章内容包括:

  • 理解序列到序列数据
  • 构建序列到序列机器翻译模型
  • 训练和评估序列到序列模型
  • 将训练的模型用于生成未见过的文本的翻译

在上一章中,我们探讨了使用深度递归神经网络解决自然语言处理任务的语言建模。在本章中,我们将进一步探讨如何使用递归神经网络解决更复杂的任务。我们将学习各种任务,其中任意长度的输入序列映射到另一个任意长度的序列。机器翻译是这种情况的一个非常适当的例子,它涉及将一种语言中的单词序列转换为另一种语言的单词序列。

此章节的主要目的是构建一个英德机器翻译器。我们首先需要下载一个机器翻译数据集,了解该数据集的结构并进行一些处理以准备好模型。接下来我们将定义一个可以将任意长的序列映射到另一个任意长的序列的机器翻译模型,这是一个基于编码器-解码器的模型,意味着有一个编码器将一个序列(例如一个英语短语)输出为一个潜在表示,并且有一个解码器来解码这个信息以生成目标序列(例如一个德语短语)。此模型的一个特殊特点是其能够内部将原始字符串转换为数值表示。因此,与我们在先前章节创建的其他自然语言处理模型相比,此模型更为全面。定义好模型后,我们将使用处理过的数据集进行训练,并评估其生成序列的每个单词的准确性以及 BLEU(双语评估研究)。BLEU 是一种比准确性更高级的度量,可以模拟人类评估翻译质量的方式。最后,我们将定义一个略微修改过的解码器,该解码器可以递归地生成单词(从一个初始种子开始),同时将前一个预测作为当前时间步的输入。在第一部分中,我们将讨论机器翻译数据,然后深入探讨建模。

11.1 理解机器翻译数据

您正在为前往德国的游客开发一项机器翻译服务。您找到了一份包含英语和德语文本的双语平行语料库(可在www.manythings.org/anki/deu-eng.zip找到)。它在文本文件中并排包含英语文本和相应的德语翻译。这个想法是使用它来训练一个序列到序列模型,在这之前,您必须了解数据的组织方式,将其加载到内存中,并分析词汇量和序列长度。此外,您将处理文本,使其在德语翻译的开头具有特殊标记“sos”(表示“句子开始”)并在翻译的结尾具有“eos”(表示“句子结束”)。这些是重要的标记,在生成模型的翻译时将对我们有所帮助。

让我们首先下载数据集并对其进行浏览。您需要手动下载此数据集(可在www.manythings.org/anki/deu-eng.zip找到),因为此网页不支持通过脚本进行自动检索。下载后,我们将提取包含数据的文本文件:

import os
import requests
import zipfile
# Make sure the zip file has been downloaded
if not os.path.exists(os.path.join('data','deu-eng.zip')):
    raise FileNotFoundError(
        "Uh oh! Did you download the deu-eng.zip from 
➥ http:/ /www.manythings.org/anki/deu-eng.zip manually and place it in the 
➥ Ch11/data folder?"
    )
else:
    if not os.path.exists(os.path.join('data', 'deu.txt')):
        with zipfile.ZipFile(os.path.join('data','deu-eng.zip'), 'r') as zip_ref:
            zip_ref.extractall('data')
    else:
        print("The extracted data already exists")

如果你打开文本文件,它将有以下条目:

Go.    Geh.    CC-BY 2.0 (France) Attribution: tatoeba.org 
➥ #2877272 (CM) & #8597805 (Roujin)
Hi.    Hallo!    CC-BY 2.0 (France) Attribution: tatoeba.org 
➥ #538123 (CM) & #380701 (cburgmer)
Hi.    Grüß Gott!    CC-BY 2.0 (France) Attribution: 
➥ tatoeba.org #538123 (CM) & #659813 (Esperantostern)
...
If someone who doesn't know your background says that you sound like 
➥ a native speaker, ... . In other words, you don't really sound like 
➥ a native speaker.    Wenn jemand, der nicht weiß, woher man 
➥ kommt, sagt, man erwecke doch den Eindruck, Muttersprachler zu sein, 
➥ ... - dass man diesen Eindruck mit anderen Worten eigentlich nicht 
➥ erweckt.    CC-BY 2.0 (France) Attribution: tatoeba.org #953936 
➥  (CK) & #8836704 (Pfirsichbaeumchen)
Doubtless there exists in this world precisely the right woman for 
➥ any given man to marry and vice versa; ..., that probably, since 
➥ the earth was created, the right man has never yet met the right 
➥ woman.    Ohne Zweifel findet sich auf dieser Welt zu jedem Mann 
➥ genau die richtige Ehefrau und umgekehrt; ..., dass seit Erschaffung 
➥ ebenderselben wohl noch nie der richtige Mann der richtigen Frau 
➥ begegnet ist.    CC-BY 2.0 (France) Attribution: tatoeba.org 
➥ #7697649 (RM) & #7729416 (Pfirsichbaeumchen)

数据以制表符分隔的格式呈现,并具有<德语短语><制表符><英语短语><制表符><归属>格式。我们真正关心记录中的前两个以制表符分隔的值。一旦数据下载完成,我们就可以轻松地将数据加载到 pandas DataFrame 中。在这里,我们将加载数据,设置列名,并提取我们感兴趣的列:

import pandas as pd
# Read the csv file
df = pd.read_csv(
    os.path.join('data', 'deu.txt'), delimiter='\t', header=None
)
# Set column names
df.columns = ["EN", "DE", "Attribution"]
df = df[["EN", "DE"]]

我们还可以通过以下方式计算 DataFrame 的大小

print('df.shape = {}'.format(df.shape))

这将返回

df.shape = (227080, 2)

注意:这里的数据会随着时间而更新。因此,您可能会得到与此处显示的略有不同的结果(例如,数据集大小,词汇量,词汇分布等)。

我们的数据集中有约 227,000 个示例。每个示例都包含一个英语短语/句子/段落和相应的德语翻译。我们将再进行一次清理步骤。看起来文本文件中的一些条目存在一些 Unicode 问题。这些问题对于 pandas 来说处理得很好,但对于一些下游 TensorFlow 组件来说会有问题。因此,让我们运行以下清理步骤来忽略数据中的这些问题行:

clean_inds = [i for i in range(len(df)) if b"\xc2" not in df.iloc[i]["DE"].encode("utf-8")]
df = df.iloc[clean_inds]

让我们通过调用 df.head()(表 11.1)和 df.tail()(表 11.2)来分析一些示例。df.head()返回表 11.1 的内容,而 df.tail()生成表 11.2 的内容。

表 11.1 数据开头的一些示例

EN DE
0 Go. Geh.
1 Hi. Hallo!
2 Hi. Grüß Gott!
3 Run! Lauf!
4 Run. Lauf!

表 11.2 数据结尾的一些示例

EN DE
227075 Even if some by non-native speakers… Auch wenn Sätze von Nichtmuttersprachlern mitu…
227076 如果一个不了解你的背景的人… 如果一个不了解你的背景的人…
227077 如果一个不了解你的背景的人… 如果一个陌生人告诉你要按照他们…
227078 如果一个不了解你的背景的人… 如果一个不知道你来自哪里的人…
227079 这个世界上肯定存在… 毫无疑问,这个世界上肯定存在…

示例按长度排序,你可以看到它们从一个单词的示例开始,然后以大约 50 个单词的示例结束。我们将只使用来自该数据集的 50,000 个短语的样本来加快工作流程:

n_samples = 50000
df = df.sample(n=n_samples, random_state=random_seed)

我们设置随机种子为 random_seed=4321。

最后,我们将在德语翻译中引入两个特殊标记:sos 和 eos。sos 标记翻译的开始,eos 标记翻译的结束。正如您将看到的,这些标记在训练后生成翻译时起着重要作用。但为了在训练和推断(或生成)期间保持一致,我们将这些标记引入到所有示例中。可以使用以下方式轻松完成此操作:

start_token = 'sos'
end_token = 'eos'
df["DE"] = start_token + ' ' + df["DE"] + ' ' + end_token

SOS 和 EOS 标记

SOS 和 EOS 的选择只是一种便利,从技术上讲,它们可以由任何两个唯一的标记表示,只要它们不是语料库本身的词汇。使这些标记唯一是重要的,因为当从以前未见过的英文句子生成翻译时,它们起着重要作用。这些作用的具体细节将在后面的部分中讨论。

这是一个非常直接的转换。这将把短语“Grüß Gott!”转换为“sos Grüß Gott!eos”。接下来,我们将从我们抽样的数据中生成一个训练/验证/测试子集:

# Randomly sample 10% examples from the total 50000 randomly
test_df = df.sample(n=n=int(n_samples/10), random_state=random_seed)
# Randomly sample 10% examples from the remaining randomly
valid_df = df.loc[~df.index.isin(test_df.index)].sample(
    n=n=int(n_samples/10), random_state=random_seed
)
# Assign the rest to training data
train_df = df.loc[~(df.index.isin(test_df.index) | 
➥ df.index.isin(valid_df.index))]

我们将把数据的 10%保留为测试数据,另外 10%保留为验证数据,剩下的 80%作为训练数据。数据集将随机抽样(无替换)以得到数据集。然后我们继续分析文本数据集的两个重要特征,就像我们一遍又一遍地做的那样:词汇大小(列表 11.1)和序列长度(列表 11.2)。

列表 11.1 分析词汇大小

from collections import Counter
en_words = train_df["EN"].str.split().sum()                    ❶
de_words = train_df["DE"].str.split().sum()                    ❷
n=10                                                           ❸
def get_vocabulary_size_greater_than(words, n, verbose=True):
    """ Get the vocabulary size above a certain threshold """
    counter = Counter(words)                                   ❹
    freq_df = pd.Series(                                       ❺
        list(counter.values()), 
        index=list(counter.keys())
    ).sort_values(ascending=False)
    if verbose:
        print(freq_df.head(n=10))                              ❻
    n_vocab = (freq_df>=n).sum()                               ❼
    if verbose:
        print("\nVocabulary size (>={} frequent): {}".format(n, n_vocab))
    return n_vocab
print("English corpus")
print('='*50)
en_vocab = get_vocabulary_size_greater_than(en_words, n)
print("\nGerman corpus")
print('='*50)
de_vocab = get_vocabulary_size_greater_than(de_words, n)

❶ 从英文单词中创建一个扁平化列表。

❷ 创建一个扁平化的德文单词列表。

❸ 获取出现次数大于或等于 10 次的单词的词汇大小。

❹ 生成一个计数器对象(即 dict word -> frequency)。

❺ 从计数器创建一个 pandas 系列,然后按最频繁到最不频繁排序。

❻ 打印最常见的单词。

❼ 获取至少出现 10 次的单词的计数。

这将返回

English corpus
==================================================
Tom    9427
to     8673
I      8436
the    6999
you    6125
a      5680
is     4374
in     2664
of     2613
was    2298
dtype: int64
Vocabulary size (>=10 frequent): 2238
German corpus
==================================================
sos      40000
eos      40000
Tom       9928
Ich       7749
ist       4753
nicht     4414
zu        3583
Sie       3465
du        3112
das       2909
dtype: int64
Vocabulary size (>=10 frequent): 2497

接下来,在以下函数中进行序列分析。

列表 11.2 分析序列长度

def print_sequence_length(str_ser):
    """ Print the summary stats of the sequence length """
    seq_length_ser = str_ser.str.split(' ').str.len()             ❶
    print("\nSome summary statistics")                            ❷
    print("Median length: {}\n".format(seq_length_ser.median()))  ❷
    print(seq_length_ser.describe())                              ❷
    print(
        "\nComputing the statistics between the 1% and 99% quantiles (to 
➥ ignore outliers)"
    )
    p_01 = seq_length_ser.quantile(0.01)                          ❸
    p_99 = seq_length_ser.quantile(0.99)                          ❸
    print(
        seq_length_ser[
            (seq_length_ser >= p_01) & (seq_length_ser < p_99)
        ].describe()                                              ❹
    )

❶ 创建包含每个评论的序列长度的 pd.Series。

❷ 获取序列长度的中位数以及摘要统计信息。

❸ 获取给定标记(即 1%和 99%的百分位)的分位数。

❹ 打印定义的分位数之间的数据的摘要统计信息。

接下来,对数据调用此函数以获取统计信息:

print("English corpus")
print('='*50)
print_sequence_length(train_df["EN"])
print("\nGerman corpus")
print('='*50)
print_sequence_length(train_df["DE"])

这产生

English corpus
==================================================
Some summary statistics
Median length: 6.0
count    40000.000000
mean         6.360650
std          2.667726
min          1.000000
25%          5.000000
50%          6.000000
75%          8.000000
max        101.000000
Name: EN, dtype: float64
Computing the statistics between the 1% and 99% quantiles (to ignore outliers)
count    39504.000000
mean         6.228002
std          2.328172
min          2.000000
25%          5.000000
50%          6.000000
75%          8.000000
max         14.000000
Name: EN, dtype: float64
German corpus
==================================================
Some summary statistics
Median length: 8.0
count    40000.000000
mean         8.397875
std          2.652027
min          3.000000
25%          7.000000
50%          8.000000
75%         10.000000
max         77.000000
Name: DE, dtype: float64
Computing the statistics between the 1% and 99% quantiles (to ignore outliers)
count    39166.000000
mean         8.299035
std          2.291474
min          5.000000
25%          7.000000
50%          8.000000
75%         10.000000
max         16.000000
Name: DE, dtype: float64

接下来,让我们打印出两种语言的词汇量和序列长度参数:

print("EN vocabulary size: {}".format(en_vocab))
print("DE vocabulary size: {}".format(de_vocab))
# Define sequence lengths with some extra space for longer sequences
en_seq_length = 19
de_seq_length = 21
print("EN max sequence length: {}".format(en_seq_length))
print("DE max sequence length: {}".format(de_seq_length))

这将返回

EN vocabulary size: 359
DE vocabulary size: 336
EN max sequence length: 19
DE max sequence length: 21

现在我们有了定义模型所需的语言特定参数。在下一节中,我们将看看如何定义一个能够在语言之间进行翻译的模型。

练习 1

您已经获得了以下格式的 pandas Series ser:

0       [a, b, c]
1          [d, e]
2    [f, g, h, i]
...
dtype: object

编写一个名为 vocab_size(ser)的函数来返回词汇量。

11.2 编写英语-德语 seq2seq 机器翻译器

您有一个准备进入模型的干净数据集。您将使用一个序列到序列的深度学习模型作为机器翻译模型。它由两部分组成:一个编码器,用于生成英文(源)文本的隐藏表示,以及一个解码器,用于解码该表示以生成德文(目标)文本。编码器和解码器都是循环神经网络。此外,模型将接受原始文本,并使用 TensorFlow 提供的 TextVectorization 层将原始文本转换为令牌 ID。这些令牌 ID 将传递给一个嵌入层,该层将返回令牌 ID 的单词向量。

我们已经准备好并准备好使用的数据。现在让我们了解一下可以使用此数据的模型。序列到序列学习将任意长的序列映射到另一个任意长的序列。对于我们来说,这提出了一个独特的挑战,因为模型不仅需要能够消耗任意长度的序列,还需要能够生成任意长度的序列作为输出。例如,在机器翻译中,翻译通常比输入的单词少或多。因此,它们需要一种特殊类型的模型。这些模型被称为编码器-解码器seq2seq(缩写为序列到序列)模型。

编码器-解码器模型实际上是两个不同的模型以某种方式相互连接起来。在概念上,编码器接受一个序列并产生一个上下文向量(或思考向量),其中嵌入了输入序列中的信息。解码器接受编码器产生的表示,并对其进行解码以生成另一个序列。由于两个部分(即编码器和解码器)分别在不同的事物上操作(即编码器消耗输入序列,而解码器生成输出序列),因此编码器-解码器模型非常适合解决序列到序列的任务。理解编码器和解码器的另一种方式是:编码器处理源语言输入(即要翻译的语言),解码器处理目标语言输入(即要翻译成的语言)。如图 11.1 所示。


图 11.1 编码器-解码器架构在机器翻译环境中的高级组件

特别地,编码器包含一个循环神经网络。我们将使用门控循环单元(GRU)模型。它通过输入序列并产生一个最终输出,这是在处理输入序列中的最后一个元素之后 GRU 单元的最终输出。

思想向量

思想向量 是由深度学习领域的泰斗杰弗里·亨滕(Geoffery Hinten)推广的一个术语,他从深度学习的起源就参与其中。思想向量指的是思想的向量化表示。生成准确的思想数值表示将彻底改变我们搜索文档或在网络上搜索(例如,谷歌)的方式。这类似于数值表示单词被称为 单词向量 的方式。在机器翻译的背景下,上下文向量可以称为思想向量,因为它在一个向量中捕捉了句子或短语的本质。

您可以在wiki.pathmind.com/thought-vectors阅读更多关于此的信息。

接下来,我们有解码器,它也由一个 GRU 模型和几个密集层组成。密集层的目的是生成最终的预测(目标词汇中的一个词)。解码器中存在的密集层的权重在时间上是共享的。这意味着,正如 GRU 层在从一个输入移动到另一个输入时更新相同的权重一样,密集层在时间步上重复使用相同的权重。这个过程在图 11.2 中有所描述。


图 11.2 编码器和解码器模块中的特定组件。编码器有一个 GRU 层,解码器由一个或多个密集层后跟的 GRU 层组成,其权重在时间上是共享的。

到目前为止,在解决 NLP 任务时,将字符串标记转换为数值 ID 被认为是预处理步骤。换句话说,我们会执行标记到 ID 的转换,并将 ID 输入模型。但它并不一定要这样。我们可以定义更加灵活的模型,让这种文本处理在内部完成并学会解决任务。Keras 提供了一些层,可以插入到您的模型中,以使其更加端到端。tensorflow.keras.layers.experimental.preprocessing.TextVectorization 层就是这样一种层。让我们来看看这个层的用法。

TensorFlow 实战(五)(2)https://developer.aliyun.com/article/1522831

相关文章
|
5月前
|
机器学习/深度学习 TensorFlow API
TensorFlow与Keras实战:构建深度学习模型
本文探讨了TensorFlow和其高级API Keras在深度学习中的应用。TensorFlow是Google开发的高性能开源框架,支持分布式计算,而Keras以其用户友好和模块化设计简化了神经网络构建。通过一个手写数字识别的实战案例,展示了如何使用Keras加载MNIST数据集、构建CNN模型、训练及评估模型,并进行预测。案例详述了数据预处理、模型构建、训练过程和预测新图像的步骤,为读者提供TensorFlow和Keras的基础实践指导。
393 59
|
8天前
|
机器学习/深度学习 TensorFlow API
机器学习实战:TensorFlow在图像识别中的应用探索
【10月更文挑战第28天】随着深度学习技术的发展,图像识别取得了显著进步。TensorFlow作为Google开源的机器学习框架,凭借其强大的功能和灵活的API,在图像识别任务中广泛应用。本文通过实战案例,探讨TensorFlow在图像识别中的优势与挑战,展示如何使用TensorFlow构建和训练卷积神经网络(CNN),并评估模型的性能。尽管面临学习曲线和资源消耗等挑战,TensorFlow仍展现出广阔的应用前景。
29 5
|
3月前
|
机器学习/深度学习 存储 前端开发
实战揭秘:如何借助TensorFlow.js的强大力量,轻松将高效能的机器学习模型无缝集成到Web浏览器中,从而打造智能化的前端应用并优化用户体验
【8月更文挑战第31天】将机器学习模型集成到Web应用中,可让用户在浏览器内体验智能化功能。TensorFlow.js作为在客户端浏览器中运行的库,提供了强大支持。本文通过问答形式详细介绍如何使用TensorFlow.js将机器学习模型带入Web浏览器,并通过具体示例代码展示最佳实践。首先,需在HTML文件中引入TensorFlow.js库;接着,可通过加载预训练模型如MobileNet实现图像分类;然后,编写代码处理图像识别并显示结果;此外,还介绍了如何训练自定义模型及优化模型性能的方法,包括模型量化、剪枝和压缩等。
49 1
|
2月前
|
机器学习/深度学习 数据挖掘 TensorFlow
解锁Python数据分析新技能,TensorFlow&PyTorch双引擎驱动深度学习实战盛宴
在数据驱动时代,Python凭借简洁的语法和强大的库支持,成为数据分析与机器学习的首选语言。Pandas和NumPy是Python数据分析的基础,前者提供高效的数据处理工具,后者则支持科学计算。TensorFlow与PyTorch作为深度学习领域的两大框架,助力数据科学家构建复杂神经网络,挖掘数据深层价值。通过Python打下的坚实基础,结合TensorFlow和PyTorch的强大功能,我们能在数据科学领域探索无限可能,解决复杂问题并推动科研进步。
58 0
|
3月前
|
机器学习/深度学习 数据采集 TensorFlow
使用TensorFlow进行模型训练:一次实战探索
【8月更文挑战第22天】本文通过实战案例详解使用TensorFlow进行模型训练的过程。首先确保已安装TensorFlow,接着预处理数据,包括加载、增强及归一化。然后利用`tf.keras`构建卷积神经网络模型,并配置训练参数。最后通过回调机制训练模型,并对模型性能进行评估。此流程为机器学习项目提供了一个实用指南。
|
3月前
|
API UED 开发者
如何在Uno Platform中轻松实现流畅动画效果——从基础到优化,全方位打造用户友好的动态交互体验!
【8月更文挑战第31天】在开发跨平台应用时,确保用户界面流畅且具吸引力至关重要。Uno Platform 作为多端统一的开发框架,不仅支持跨系统应用开发,还能通过优化实现流畅动画,增强用户体验。本文探讨了Uno Platform中实现流畅动画的多个方面,包括动画基础、性能优化、实践技巧及问题排查,帮助开发者掌握具体优化策略,提升应用质量与用户满意度。通过合理利用故事板、减少布局复杂性、使用硬件加速等技术,结合异步方法与预设缓存技巧,开发者能够创建美观且流畅的动画效果。
77 0
|
3月前
|
安全 Apache 数据安全/隐私保护
你的Wicket应用安全吗?揭秘在Apache Wicket中实现坚不可摧的安全认证策略
【8月更文挑战第31天】在当前的网络环境中,安全性是任何应用程序的关键考量。Apache Wicket 是一个强大的 Java Web 框架,提供了丰富的工具和组件,帮助开发者构建安全的 Web 应用程序。本文介绍了如何在 Wicket 中实现安全认证,
43 0
|
3月前
|
机器学习/深度学习 数据采集 TensorFlow
从零到精通:TensorFlow与卷积神经网络(CNN)助你成为图像识别高手的终极指南——深入浅出教你搭建首个猫狗分类器,附带实战代码与训练技巧揭秘
【8月更文挑战第31天】本文通过杂文形式介绍了如何利用 TensorFlow 和卷积神经网络(CNN)构建图像识别系统,详细演示了从数据准备、模型构建到训练与评估的全过程。通过具体示例代码,展示了使用 Keras API 训练猫狗分类器的步骤,旨在帮助读者掌握图像识别的核心技术。此外,还探讨了图像识别在物体检测、语义分割等领域的广泛应用前景。
23 0
|
4月前
|
机器学习/深度学习 数据挖掘 TensorFlow
解锁Python数据分析新技能,TensorFlow&PyTorch双引擎驱动深度学习实战盛宴
【7月更文挑战第31天】在数据驱动时代,Python凭借其简洁性与强大的库支持,成为数据分析与机器学习的首选语言。**数据分析基础**从Pandas和NumPy开始,Pandas简化了数据处理和清洗,NumPy支持高效的数学运算。例如,加载并清洗CSV数据、计算总销售额等。
58 2
|
4月前
|
机器学习/深度学习 数据挖掘 TensorFlow
数据界的“福尔摩斯”如何炼成?Python+TensorFlow数据分析实战全攻略
【7月更文挑战第30天】数据界的“福尔摩斯”运用Python与TensorFlow解开数据之谜。
50 2
下一篇
无影云桌面