热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

转载|使用PaddleFluid和TensorFlow训练序列标注模型

上一篇通过转载|使用PaddleFluid和TensorFlow训练RNN语言模型大家了解了:在PaddleFluid和TensorFlow平台下如何组

上一篇通过转载|使用PaddleFluid和TensorFlow训练RNN语言模型大家了解了:

  • 在 PaddleFluid 和 TensorFlow 平台下如何组织序列输入数据;

  • 如何使用循环神经网络单元;

  • 使用中的注意事项。

可以看到 PaddleFluid 中的各种循环神经网络单元都直接支持非填充序列作为输入,用户在使用时无需对 mini-batch 中的不等长序列进行填充,无需关心填充位是否会对代价(loss)计算产生影响,从而需要在计算损失时对填充位置进行过滤这样的细节,对使用来说无疑是十分方便的。 

循环神经网络的是深度学习模型中最为重要的一部分,这一篇我们以序列标注任务为例将会构造一个更加复杂的循环神经网络模型用于命名实体识别任务。我们的关注点始终放在:在两个平台下:(1)如何组织序列数据;(2)如何使用序列处理单元(不限于循环神经网络)。

这一篇会看到: 

1. PaddleFluid Data Feeder vs. 使用 TensorFlow r1.4 之后 release 的 Dataset API 读取数据; 

2. 在 PaddleFluid 和 TensorFlow 中,使用条件随机场(Conditional Random Field,CRF)单元; 

3. 在 PaddleFluid 和 TensorFlow 中,通过数据并行方式使用多块 GPU 卡进行训练。

如何使用代码

本篇文章配套有完整可运行的代码, 请随时从 github [1] 上获取最新代码。代码包括以下几个文件:

在执行训练任务前,请首先在终端执行下面的命令进行训练数据下载以及预处理。

sh download.sh

在终端运行以下命令便可以使用默认结构和默认参数运行 PaddleFluid 训练序列标注模型。

python sequence_tagging_fluid.py

在终端运行以下命令便可以使用默认结构和默认参数运行 TensorFlow 训练序列标注模型。

python sequence_tagging_tensorflow.py背景介绍

序列标注和命名实体识别

序列标注是自然语言处理任务中的重要基础任务之一。常见的分词,词性标注,语义角色标注,命名实体识别,甚至自动问答(QA)都可以通过序列标注模型来实现。这一篇我们将训练一个序列标注模型完成命名实体识别的任务。

我们先来看看,什么是序列标注问题呢?请看下面一幅图:

▲ 图1. 序列标注问题

序列标注任务是为一个一维的线性输入序列中的每个元素打上标签集合中的某个标签。在上面的例子中,序列标注就是为图像序列中的每个元素贴上一个描述它们形状的标签。而序列标注任务的难点在于:序列中 元素的标记和 它们在序列中的位置密切相关。 

那么, 什么是命名实体识别呢?命名实体识别(Named Entity Recognition,NER)又称作“专名识别”,是指识别文本中具有特定意义的实体,主要包括:人名、地名、机构名、专有名词等。

BIO 表示法 

序列标注任务一般都会采用 BIO 表示方式来定义序列标注的标签集,B 代表句子的开始,I 代表句子中间,O 代表句子结束。通过 B、I、O 三种标记将不同的语块赋予不同的标签,例如:对于一个标记为 A 的命名实体,将它所包含的第一个语块赋予标签 B-A,将它所包含的其它语块赋予标签 I-A,不属于任何命名实体的语块赋予标签 O。图 2 是用 BIO 表示标注序列中命名实体的具体示例。

▲ 图2. BIO标注方法示例

模型概览

图 3 是本篇模型的模型结构概览。 

▲ 图3. 序列标注模型结构概览

我们要训练的序列标注模型,接受:一个文本序列作为输入,另一个与输入文本序列等长的标记序列作为学习的目标。首先通过上一篇介绍过的 word embedding 层的取词作用得到词向量, 接着经过一个双向 LSTM 单元学习序列的特征表示,这个特别表示最终作为条件随机场 CRF 的输入完成最终的序列标注任务。 

下面是对各个子模块的进一步说明。

双向循环神经网络 

在循环神经网络模型中,t 时刻输出的隐藏层向量编码了到 t 时刻为止所有输入的信息,但由于循环神经网络单元计算的串行行:t 时刻循环神经网络但愿可以看到历史(t 时刻之前),却无法看到未来(t 时刻之后)。

一些自然语言处理任务总是能一次性拿到整个句子,这种情况下,在 t 时刻计算时,如果能够像获取历史信息一样得到未来的信息,对序列学习任务会有很大帮助,双向循环神经网络的出现正是为了解决这一问题。

它的思想简单且直接:使用两个循环神经网络单元( simple RNN,GRU 或者 LSTM 均可)分别以正向和反向顺序学习输入序列,再将两者的输出 向量进行横向拼接。这样的一个输出向量中就既包含了 t 时刻之前的信息,也包含了 t 时刻之后的信息。

条件随机场 

使用神经网络模型解决问题的思路通常都是:前层网络学习输入的特征表示,网络的最后一层在特征基础上完成最终任务。在序列 标注任务中,双向循环神经网络学习输入的特征表示,条件随机场(Conditional Random Filed, CRF)正是在特征的基础上完成序列标注的一种计算单元,处于整个网络的末端。

CRF 是一种概率化结构模型,可以看作是一个概率无向图模型(也叫作马尔科夫随机场),结点表示随机变量,边表示随机变量之间的概率依赖关系。简单来讲 CRF 学习条件概率:P(X|Y),其中 X=(x1,x2,...,xn) 是输入序列,Y=(y1,y2,...,yn) 是标记序列;解码过程是给定 X 序列求解令 P(Y|X) 最大的 Y 序列,即

条件随机场是的定义:设 G=(V,E) 是一个无向图, V 是结点的集合,E 是无向边的集合。V 中的每个结点对应一个随机变量 Yv,,其取值范围为可能的标记集合 {y},如果以随机变量 X 为条件,每个随机变量 Yv 都满足以下马尔科夫特性: 

其中,ω∼v 表示两个结点在图 G 中是邻近结点,那么,(X,Y) 是一个条件随机场。

线性链条件随机场 

上面的定义并没有对 X 和 Y 的结构给出更多约束,理论上来讲只要标记序列表示了一定的条件独立性,G 的图结构可以是任意的。对序列标注任务,只需要考虑 X 和 Y 都是一个序列,于是可以形成一个如图 4 所示的简单链式结构图。在图中,输入序列 X 的元素之间并不存在图结构,因为我们只是将它作为条件,并不做任何条件独立假设。

▲ 图4. 输入序列和标记序列具有相同结构的线性链条件随机场

序列标注问题使用的是以上这种定义在线性链上的特殊条件随机场,称之为线性链条件随机场(Linear Chain Conditional Random Field)。下面,我们给出线性链条件随机场的数学定义: 

定义 2 :线性链条件随机场 :设 X=(x1,x2,...,xn),Y=(y1,y2,...,yn) 均为线性链表示的随机变量序列,若在给定随机变量序列 X 的条件下,随机变量序列 Y 的条件概率分布 P(Y|X) 满足马尔科夫性:

i=1,2,...,n(在i=1和n时只考虑单边)则称 P(Y|X) 为线性链条件随机场。X 表示输入序列,Y 表示与之对应的标记序列。

根据线性链条件随机场上的因子分解定理,在给定观测序列 X 时,一个特定标记序列 Y 的概率可以定义为:

其中:

是规范化因子。

上面的式子中 tj 是定义在边上的特征函数,依赖于当前和前一个位置,称为转移特征,表示对于观察序列 X 及其标注序列在 i 及 i−1 位置上标记的转移概率。sk 是定义在结点上的特征函数,称为状态特征,依赖于当前位置,表示对于观察序列 X 及其 i 位置的标记概率。λj 和 μk 分别是转移特征函数和状态特征函数对应的权值。

线性链条件随机场的优化目标 

实际上 ,t 和 s 可以用相同的数学形式表示,s 可以同样也写为以下形式:

假设有 K1 个转移特征,K2 个状态特征,定义特征函数:

再对转移特征和状态特在各个位置 i 求和有:

于是条件概率 P(Y|X) 可以写为:

我们把 f 统称为特征函数,ω 是权值,是 CRF 模型要求解的参数。

学习时,对于给定的输入序列和对应的标记序列的集合 D=[(X1,Y1),(X2,Y2),...,(XN,YN)] ,通过正则化的极大似然估计,可以得到如下优化目标:

这个优化目标,可以通过反向传播算法和整个神经网络一起更新求解。 

解码时,对于给定的输入序列 X,通过解码算法(通常有:维特比算法、Beam Search)求令出条件概率最大的输出序列

CRF小结

条件随机场是这一篇网络中一个相对复杂的计算单元。值得庆幸的是,在各个深度学习框架的帮助下,大多数情况下,我们只需要知道其原理便可以非常方便的使用,而不必过于关注 其内部的实现细节。

这里我们再对上面的内容进行一个简单的总结,方便大家使用 CRF 单元:

1. 在序列标注网络中, CRF 以循环神经网络单元输出向量作为输入,学习状态特征和转移特征。

2. 状态特征只与当然输入有关;转移特征是一个矩阵,刻画了标记两两之间互相转移的强度。

3. 假设循环神经网络单元输出向量维度为 h ,序列中含有 t 个词语,共有 d 个标记:

  • 循环神经网络输入矩阵的大小为:Out=t×h;

     

  • CRF 层以 Out 为输入学习转移特征:通过一个 全连接层将 Out 映射为一个 t×d 的矩阵,也就是转移特征; 

  • 状态特征是一个:(d+2)×d 维的矩阵,刻画了标记之前转移的强度。 这里的 +2 是需要学习序列开始 向句子首词转移和和句子末尾词向序列结束 转移这样两种特殊的状态转移;

  • CRF 本质上计算了一个 softmax:给定标记序列出现的概率。但困难之处在于 softmax 的归一化分母是所有可能标记序列,计算量很大。但由于引入了马尔科夫假设,这个归一化分母可以巧妙地通过一个动态规划算法求解。 

4. CRF 的学习准则是令 negative log likelihood 最大化。

数据集介绍

这一篇我们使用 Standford CS224d 课程中作业 2 [2] 的 NER 任务数据作为训练数据源。 进入 data 目录运行 data/download.sh 脚本下载数据并预处理训练数据。预处理包括:1. 为输入文本序列建立词典;2. 组织输入数据格式。 

运行结束将会在 data 目录下看到如下内容。

data
├── dev
├── dev_src.txt
├── dev_src.vocab
├── dev_trg.txt
├── dev_trg.vocab
├── download.sh
├── preprocess.py
├── train
├── train_src.txt
├── train_src.vocab
├── train_trg.txt
└── train_trg.vocab

其中需要重点关注的是 train_src.txt 、 train_trg.txt 、 train_src.vocab和train_trg.vocab文件。它们分别是:输入文本序列;文本对应的标记序列;输入文本序列的词典以及标记序列词典。 train_src.txt 和 train_trg.txt 的一行是一条训练样本,他们严格一一对应。分别执行head -n 1 train_src.txt 和 head -n 1 train_trg.t xt 会看到如下内容:

EU rejects German call to boycott British lamb .

B-ORG O B-MISC O O O B-MISC O O程序结构

我们首先在此整体回顾一下使用 PaddleFluid 平台和 TensorFlow 运行神经网络模型的整体流程。

PaddleFluid

1. 调用 PaddleFluid API 描述神经网络模型。PaddleFluid 中 一个神经网络训练任务被称之为一段 Fluid Program 。 

2. 定义 Fluid Program 执行设备: place 。常见的有 fluid.CUDAPlace(0) 和fluid.CPUPlace() 。

place = fluid.CUDAPlace(0) if conf.use_gpu else fluid.CPUPlace()

注:PaddleFluid 支持混合设备运行,一些 运算(operator)没有特定设备实现,或者为了提高全局资源利用率,可以为他们指定不同的计算设备。

3. 创建 PaddleFluid 执行器(Executor),需要为执行器指定运行设备。

exe = fluid.Executor(place)

4. 让执行器执行 fluid.default_startup_program() ,初始化神经网络中的可学习参数,完成必要的初始化工作。 

5. 定义 DataFeeder,编写 data reader,只需要关注如何返回一条训练/测试数据。 

6. 进入训练的双层循环(外层在 epoch 上循环,内层在 mini-batch 上循环),直到训练结束。

TensorFlow 

1. 调用 TensorFlow API 描述神经网络模型。 TensorFlow 中一个神经网络模型是一个 Computation Graph。

2. 创建 TensorFlow Session 用来执行计算图。

sess = tf.Session()

3. 调用 sess.run(tf.global_variables_initializer()) 初始化神经网络中的可学习参数。

4. 编写返回每个 mini-batch 数据的数据读取脚本。

5. 进入训练的双层循环(外层在 epoch 上循环,内层在 mini-batch 上循环),直到训练结束。

如果不显示地指定使用何种设备进行训练,TensorFlow 会对机器硬件进行检测(是否有 GPU), 选择能够尽可能利用机器硬件资源的方式运行。 

构建网络

基于 PaddleFluid 和 TensorFlow 的序列标注网络分别定义在 sequence_tagging_fluid.py 和 sequence_tagging_tensorflow.py 的 NER_net 类中,详细信息请参考完整代码,这里对重要部分进行说明。 

加载训练数据 

PaddleFluid:编写Data Reader 

PaddleFluid 模型通过 fluid.layers.data 来接收输入数据。序列标注网络以图片以及图片对应的类别标签作为网络的输入:

self.source = fluid.layers.data(name="source", shape=[1], dtype="int64", lod_level=1)
self.target = fluid.layers.data(name="target", shape=[1], dtype="int64", lod_level=1)

定义 data layer 的核心是指定输入 Tensor 的形状( shape )和类型。

序列标注中,输入文本序列和标记序列都使用 one-hot 特征作为输入,一个词用一个和字典大小相同的向量表示,每一个位置对应了字典中的 一个词语。one-hot 向量仅有一个维度为 1, 其余全部为 0。在上面定义的 data layer 中 source 和 target 的形状都是 1,类型是 int64 。 

PaddleFluid 支持非填充的序列输入,这是通过 LoD Tensor 实现的。关于什么是 LoD Tensor请参考上一篇使用 PaddleFluid 和 TensorFlow 训练 RNN 语言模型中的介绍,这一篇不再赘述。有了 LoD Tensor 的概念后,在 PaddleFluid 中,通过 DataFeeder 模块来为网络中的 data layer 提供数据,调用方式如下面的代码所示:

train_reader = paddle.batch(paddle.reader.shuffle(data_reader(conf.train_src_file_name, conf.train_trg_file_name,conf.src_vocab_file, conf.trg_vocab_file),buf_size=1024000),batch_size=conf.batch_size)place = fluid.CUDAPlace(0) if conf.use_gpu else fluid.CPUPlace()
feeder = fluid.DataFeeder(feed_list=[net.source, net.target], place=place)

观察以上代码,需要用户完成的仅有:编写一个实现读取一条数据的 python 函数:data_reader 。 data_reader 的代码非常简单,我们再来看一下它的具体实现:

def data_reader(src_file_name, trg_file_name, src_vocab_file, trg_vocab_file):def __load_dict(dict_file_path):word_dict &#61; {}with open(dict_file_path, "r") as fdict:for idx, line in enumerate(fdict):if idx < 2: continueword_dict[line.strip().split("\t")[0]] &#61; idx - 2return word_dictdef __reader():src_dict &#61; __load_dict(src_vocab_file)trg_dict &#61; __load_dict(trg_vocab_file)with open(src_file_name, "r") as fsrc, open(trg_file_name,"r") as ftrg:for src, trg in izip(fsrc, ftrg):src_words &#61; src.strip().split()trg_words &#61; trg.strip().split()src_ids &#61; [src_dict[w] for w in src_words]trg_ids &#61; [trg_dict[w] for w in trg_words]yield src_ids, trg_idsreturn __reader

在上面的代码中&#xff1a; 

1. data_reader 是一个 python generator &#xff0c;函数名字可以任意指定&#xff0c;无需固定。 

2. data_reader 打开输入序列文件和标记序列文件&#xff0c;每次从这两个文件读取一行&#xff0c;一行既是一条训练数据&#xff0c;返回一个 python list&#xff0c;这个 python list 既是序列中所有时间步。具体的数据组织方式如下表所示&#xff0c;其中 i 代表一个整数&#xff1a;

3. paddle.batch() 接口用来构造 mini-batch 输入&#xff0c;会调用 data_reader 将数据读入一个 pool 中&#xff0c;对 pool 中的数据进行 shuffle&#xff0c;然后依次返回每个 mini-batch 的数据。

TensorFlow&#xff1a;使用Dataset API

在之前的篇章中我们都使用 TensorFlow 的 placeholder 接入训练数据&#xff0c;这一篇我们使用一种新的方式 TensorFlow 在 r1.3 版本之后引入的 Dataset API 来读取数据。

参考 Google 官方给出的 Dataset API 中的类图 [3]&#xff0c;使用 TensorFlow 的 Dataset API&#xff0c;首先引入两个抽象概念&#xff1a;

1. tf.data.Dataset 表示一系列元素&#xff0c;其中每个元素包含一个或多个 Tensor 对象。

2. tf.data.Iterator 提供了从数据集中取出元素的方法。 Iterator.get_next() 会在执行时生成Dataset 的下一个 /mini-batch 元素。

定义 Dataset 

目前 Dataset API 还提供了三种预定义好的定义 Dataset 的方式。这一篇中我们主要面向文本数据的处理&#xff0c;使用其中的 TextLineDataset 接口。 

tf.data.TextLineDataset&#xff1a;接口的输入是一个文件列表&#xff0c;输出是一个 TensorFlow dataset &#xff0c;dataset 中的每一个元素就对应了文件中的一行。通过下面的调用传入输入序列文本路径和标记序列文本路径便可返回一个 Dataset 。

src_dataset &#61; tf.data.TextLineDataset(src_file_name)
trg_dataset &#61; tf.data.TextLineDataset(trg_file_name)

获取 Iterator 

需要说明的是&#xff0c;TensorFlow 中的循环神经网络要求一个 mini-batch 之内序列长度相等&#xff0c;使用 Dynamic RNN 时&#xff0c;batch 和 batch 之间序列长度可以不相等&#xff0c;因此对一个 mini-batch 之内的数据需要进行填充。 

Dataset API 提供了 padded_batch 帮助构造填充后的 mini-batch 数据。 

提示&#xff1a;使用 bucket 分桶&#xff0c;从桶内取 mini-batch 数据&#xff0c;填充至一个 batch 中的最长序列长度能够有效提高 dynamic rnn 的计算效率。 

下面的代码返回 Iterator &#xff0c;使用先分桶&#xff0c;然后再取 mini-batch 数据填充至  batch 中最长序列长度的方式。完整代码请参考&#xff1a;iterator_helper_tf [4]。

def get_data_iterator(src_file_name,trg_file_name,src_vocab_file,trg_vocab_file,batch_size,pad_token&#61;"

",max_sequence_length&#61;None,unk_id&#61;1,num_parallel_calls&#61;4,num_buckets&#61;5,output_buffer_size&#61;102400,is_training&#61;True):def __get_word_dict(vocab_file_path, unk_id):return tf.contrib.lookup.index_table_from_file(vocabulary_file&#61;vocab_file_path,key_column_index&#61;0,default_value&#61;unk_id)src_dataset &#61; tf.data.TextLineDataset(src_file_name)trg_dataset &#61; tf.data.TextLineDataset(trg_file_name)dataset &#61; tf.data.Dataset.zip((src_dataset, trg_dataset))if is_training:dataset &#61; dataset.shuffle(buffer_size&#61;output_buffer_size, reshuffle_each_iteration&#61;True)src_trg_dataset &#61; dataset.map(lambda src, trg: (tf.string_split([src]).values, \tf.string_split([trg]).values),num_parallel_calls&#61;num_parallel_calls).prefetch(output_buffer_size)src_dict &#61; __get_word_dict(src_vocab_file, unk_id)trg_dict &#61; __get_word_dict(trg_vocab_file, unk_id)src_pad_id &#61; tf.cast(src_dict.lookup(tf.constant(pad_token)), tf.int32)trg_pad_id &#61; tf.cast(trg_dict.lookup(tf.constant(pad_token)), tf.int32)# convert word string to word indexsrc_trg_dataset &#61; src_trg_dataset.map(lambda src, trg: (tf.cast(src_dict.lookup(src), tf.int32),tf.cast(trg_dict.lookup(trg), tf.int32)),num_parallel_calls&#61;num_parallel_calls).prefetch(output_buffer_size)# Add in sequence lengths.src_trg_dataset &#61; src_trg_dataset.map(lambda src, trg: (src, trg, tf.size(src)),num_parallel_calls&#61;num_parallel_calls).prefetch(output_buffer_size)def __batching_func(x):return x.padded_batch(batch_size,padded_shapes&#61;(tf.TensorShape([None]),  # srctf.TensorShape([None]),  # trgtf.TensorShape([]),  #seq_len),padding_values&#61;(src_pad_id, trg_pad_id, 0, ))if num_buckets > 1:def __key_func(unused_1, unused_2, seq_len):if max_sequence_length:bucket_width &#61; (max_sequence_length &#43; num_buckets - 1) // num_bucketselse:bucket_width &#61; 10bucket_id &#61; seq_len // bucket_width,return tf.to_int64(tf.minimum(num_buckets, bucket_id))def __reduce_func(unused_key, windowed_data):return __batching_func(windowed_data)batched_dataset &#61; src_trg_dataset.apply(tf.contrib.data.group_by_window(key_func&#61;__key_func,reduce_func&#61;__reduce_func,window_size&#61;batch_size))else:batched_dataset &#61; __batching_func(curwd_nxtwd_dataset)batched_iter &#61; batched_dataset.make_initializable_iterator()src_ids, trg_ids, seq_len &#61; batched_iter.get_next()return BatchedInput(initializer&#61;batched_iter.initializer,source&#61;src_ids,target&#61;trg_ids,sequence_length&#61;seq_len)

构建网络结构及运行

构建网络结构及运行的过程对两个平台上都是常规流程。

1. 构建网络时调用相关的 API 接口&#xff0c;令一个 计算单元的输出成为下一个计算单元的输入建立起网络的连通性&#xff1b;具体请参考 sequence_tagging_fluid.py 和 sequence_tagging_tensorflow.py 中 NER_net 类的实现。

2. 运行训练以及解码具体请参考 sequence_tagging_fluid.py 和 sequence_tagging_tensorflow.py 中 train 函数的实现。

模型中核心模块&#xff1a;LSTM 单元在两个平台下的差异及注意事项请参考上一篇&#xff1a;使用 PaddleFluid 和 TensorFlow 训练 RNN 语言模型&#xff0c;这里不再赘述。

总结

这一篇继续在序列标注模型中了解 PaddleFluid 和 TensorFlow 在接受序列输入&#xff0c;序列处理策略上的不同。 

1. PaddleFluid 引入了 LoD Tensor 的概念&#xff0c;所有序列处理模块&#xff08;包括所有循环神经网络单元&#xff0c;文本卷积&#xff09;都支持非填充的序列输入&#xff0c;使用时无需对 mini-batch 数据进行填充&#xff0c;也就避免了对填充位的各种特殊处理&#xff0c;这一点非常方便。 

2. TensorFlow 中的 Dynamic RNN 支持 mini-batch 之间序列不等长&#xff0c;但仍要求一个 mini-batch 内的数据填充至一样长。 

3. PaddleFluid 中通过 Data Feeder 提供训练数据&#xff0c;只需要编写一个 python generator 实现从原始输入文件中读取一条训练样本&#xff0c; 框架会完成数据 shuffle 和组织 mini-batchd 工作。 

4. 这一篇使用了 TensorFlow r1.3 后 release 的 Dataset API&#xff0c;数据读取部分也是一个 computation graph&#xff0c;能够提高 I/O 效率&#xff0c;使用相对复杂一些。 

本篇代码中提供了通过数据并行策略在 PaddleFluid 平台下使用多块 GPU 卡进行训练&#xff0c;在 TensorFlow 中使用多卡相对复杂一些&#xff0c;这些主题会在下面继续讨论。

参考文献

[1]. 本文配套代码

https://github.com/JohnRabbbit/TF2Fluid/tree/master/05_sequence_tagging

[2].  Standford CS224d课程作业2

http://cs224d.stanford.edu/assignment2/index.html

[3]. Google官方Dataset API

https://developers.googleblog.com/2017/09/introducing-tensorflow-datasets.html

[4]. iterator_helper_tf

https://github.com/JohnRabbbit/TF2Fluid/blob/master/05_sequence_tagging/iterator_helper_tf.py


推荐阅读
  • 本文提供了PyTorch框架中常用的预训练模型的下载链接及详细使用指南,涵盖ResNet、Inception、DenseNet、AlexNet、VGGNet等六大分类模型。每种模型的预训练参数均经过精心调优,适用于多种计算机视觉任务。文章不仅介绍了模型的下载方式,还详细说明了如何在实际项目中高效地加载和使用这些模型,为开发者提供全面的技术支持。 ... [详细]
  • 利用树莓派畅享落网电台音乐体验
    最近重新拾起了闲置已久的树莓派,这台小巧的开发板已经沉寂了半年多。上个月闲暇时间较多,我决定将其重新启用。恰逢落网电台进行了改版,回忆起之前在树莓派论坛上看到有人用它来播放豆瓣音乐,便萌生了同样的想法。通过一番调试,终于实现了在树莓派上流畅播放落网电台音乐的功能,带来了全新的音乐享受体验。 ... [详细]
  • 在Windows系统中安装TensorFlow GPU版的详细指南与常见问题解决
    在Windows系统中安装TensorFlow GPU版是许多深度学习初学者面临的挑战。本文详细介绍了安装过程中的每一个步骤,并针对常见的问题提供了有效的解决方案。通过本文的指导,读者可以顺利地完成安装并避免常见的陷阱。 ... [详细]
  • Node.js 配置文件管理方法详解与最佳实践
    本文详细介绍了 Node.js 中配置文件管理的方法与最佳实践,涵盖常见的配置文件格式及其优缺点,并提供了多种实用技巧和示例代码,帮助开发者高效地管理和维护项目配置,具有较高的参考价值。 ... [详细]
  • 在第七天的深度学习课程中,我们将重点探讨DGL框架的高级应用,特别是在官方文档指导下进行数据集的下载与预处理。通过详细的步骤说明和实用技巧,帮助读者高效地构建和优化图神经网络的数据管道。此外,我们还将介绍如何利用DGL提供的模块化工具,实现数据的快速加载和预处理,以提升模型训练的效率和准确性。 ... [详细]
  • TensorFlow中文社区—下载与安装 转自:http:www.tensorfly.cntfdocget_startedos_setup.html下载与安装你可以使用我们提供的二 ... [详细]
  • 本文介绍如何使用OpenCV和线性支持向量机(SVM)模型来开发一个简单的人脸识别系统,特别关注在只有一个用户数据集时的处理方法。 ... [详细]
  • 开机自启动的几种方式
    0x01快速自启动目录快速启动目录自启动方式源于Windows中的一个目录,这个目录一般叫启动或者Startup。位于该目录下的PE文件会在开机后进行自启动 ... [详细]
  • Python多线程编程技巧与实战应用详解 ... [详细]
  • Python默认字符解析:深入理解Python中的字符串处理
    在Python中,字符串是编程中最基本且常用的数据类型之一。尽管许多初学者是从C语言开始接触字符串,通常通过经典的“Hello, World!”程序入门,但Python对字符串的处理方式更为灵活和强大。本文将深入探讨Python中的字符串处理机制,包括字符串的创建、操作、格式化以及编码解码等方面,帮助读者全面理解Python字符串的特性和应用。 ... [详细]
  • 【图像分类实战】利用DenseNet在PyTorch中实现秃头识别
    本文详细介绍了如何使用DenseNet模型在PyTorch框架下实现秃头识别。首先,文章概述了项目所需的库和全局参数设置。接着,对图像进行预处理并读取数据集。随后,构建并配置DenseNet模型,设置训练和验证流程。最后,通过测试阶段验证模型性能,并提供了完整的代码实现。本文不仅涵盖了技术细节,还提供了实用的操作指南,适合初学者和有经验的研究人员参考。 ... [详细]
  • 从2019年AI顶级会议最佳论文,探索深度学习的理论根基与前沿进展 ... [详细]
  • Python与R语言在功能和应用场景上各有优势。尽管R语言在统计分析和数据可视化方面具有更强的专业性,但Python作为一种通用编程语言,适用于更广泛的领域,包括Web开发、自动化脚本和机器学习等。对于初学者而言,Python的学习曲线更为平缓,上手更加容易。此外,Python拥有庞大的社区支持和丰富的第三方库,使其在实际应用中更具灵活性和扩展性。 ... [详细]
  • 在之前的系列中,我们探讨了多个关于AI学习的基础知识点。本篇将重点深入解析NumPy这一关键库的核心功能及其广泛应用。即使您对之前提到的例子印象模糊,也无妨,我们将从头开始,详细分析其代码结构与实现逻辑,如`import numpy as np`等基础语句,帮助您全面理解NumPy在数据处理与科学计算中的重要作用。 ... [详细]
  • 如何在Linux系统中部署TensorFlow的详细指南
    本文详细介绍了在Linux系统中部署TensorFlow的过程。作者基于北京大学曹建教授的MOOC课程进行学习,但由于课程内容较旧,环境配置方面遇到了不少挑战。经过多次尝试,最终成功解决了这些问题,并总结了一套详细的安装指南,帮助初学者快速上手TensorFlow。 ... [详细]
author-avatar
唐进单
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有