文档章节

利用TensorFlow实现卷积神经网络做文本分类

AllenOR灵感
 AllenOR灵感
发布于 2017/09/10 01:28
字数 5549
阅读 10
收藏 0
点赞 0
评论 0

这篇博客是翻译Denny Britz写的使用卷积神经网络做文本分类并且在Tensorflow上面实现,作者已经授权翻译,这是原文

在这篇博客中,我们将实现一个类似于 Kim Yoon 论文中用于句子分类的卷积神经网络模型。论文中的模型在一系列文本分类任务(如情感分类)中获得了良好的分类性能,并成为新文本分类架构的标准基准。

在阅读本文之前,我假设你已经学习了基本的卷积神经网络在自然语言处理中的知识。如果还没有,那么我推荐你看这篇博客

数据获取和准备

在本博客中,我们使用的数据集是 Movie Review data from Rotten Tomatoes ,这也是论文中使用的其中一个数据集。这个数据集包含 10662 个评论样本,其中一半是正向评论,一半是负向评论。这个数据集大约有2万个词。注意,因为这个数据集很小,所以如果我们使用很复杂的模型,那么容易造成过拟合。并且,这个数据没有帮我们分离训练数据集和测试数据集。因此,我们需要自己去预处理。在这里,我们把10%的数据作为交叉验证集。在原始的论文中,作者使用十折交叉验证(10-fold cross validation)。

在博客中,我不在讲数据的预处理过程,但是你可以在这里找到预处理的代码,该代码主要有以下几个功能:

  1. 从原始数据文件中,导入正样本和负样本数据。
  2. 数据清理,使用和论文中相同的代码
  3. 将每个句子填充到最大句子长度,也就是数据集中最长的那个句子的长度,这里是59。我们填充的特殊标记是 <PAD> ,将句子填充到相同长度是非常有用的,因为它能帮助我们进行有效的批处理,因为在批处理中的每个例子都必须有相同的长度。
  4. 构建词汇索引表,将每个单词映射到 0 ~ 18765 之间(18765是词汇量大小),那么每个句子就变成了一个整数的向量。

模型

在博客中,我们所要构建的模型如下图:


第一层网络将词向量嵌入到一个低维的向量中。下一层网络就是利用多个卷积核在前一层网络上进行卷积操作。比如,每次滑动3个,4个或者5个单词。第三层网络是一个max-pool层,从而得到一个长向量,并且添加上 dropout 正则项。最后,我们使用softmax函数对进行分类。

因为,这篇博客的目的是为了学习这个架构,所有我们对原论文中的模型进行了一些简化操作,如下:

如果要将上面省略的操作添加到代码中也是非常简单的(几十行代码)。你可以看看博客最后的扩展和练习吧。

那么让我们开始吧。

实现

为了允许各种的超参数配置,我们把我们的代码放到一个TextCNN类中,并且在 init 函数中生成模型图。

import tensorflow as tf
import numpy as np

class TextCNN(object):
    """
    A CNN for text classification.
    Uses an embedding layer, followed by a convolutional, max-pooling and softmax layer.
    """
    def __init__(
      self, sequence_length, num_classes, vocab_size,
      embedding_size, filter_sizes, num_filters, l2_reg_lambda=0.0):
      # Implementation ...

为了实例化类,我们需要传递以下参数到类中:

  • sequence_length - 句子的长度。请注意,我们通过添加特殊标记,使得所欲的句子都拥有了相同的长度(我们的数据集是59)。
  • num_classes - 最后一层分类的数目,在这里我们是进行二分类(正向评论和负向评论)。
  • vocab_size - 词汇量的大小。这个参数是为了确定我们词向量嵌入层的大小,最终的总词向量维度是 [vocabulary_size, embedding_size]
  • embeddign_size - 每个单词的词向量的长度。
  • filter_sizes - 这个参数确定我们希望我们的卷积核每次覆盖几个单词。对于每个卷积核,我们都将有 num_filters 个。比如,filter_sizes = [3, 4, 5] , 这就意味着,卷积核一共有三种类型,分别是每次覆盖3个单词的卷积核,每次覆盖4个单词的卷积核和每次覆盖5个单词的卷积核。卷积核一共的数量是 3 * num_filters 个。
  • num_filters - 每个卷积核的数量(参考 filter_sizes 参数的介绍)。

输入占位符

我们首先定义需要输入到模型中的数据。

# Placeholders for input, output and dropout
self.input_x = tf.placeholder(tf.int32, [None, sequence_length], name="input_x")
self.input_y = tf.placeholder(tf.float32, [None, num_classes], name="input_y")
self.dropout_keep_prob = tf.placeholder(tf.float32, name="dropout_keep_prob")

tf.placeholder 创建了一个占位符变量,当我们在训练阶段或者测试阶段时,都可以使用它向我们的模型输入数据。第二个参数是输入张量的形状。None 的意思是,该维度的长度可以是任何值。在我们的模型中,第一个维度是批处理大小,而使用 None 来表示这个值,说明网络允许处理任意大小的批次。

在 dropout 层中,我们使用 dropout_keep_prob 参数来控制神经元的激活程度。但这个参数,我们只在训练的时候开启,在测试的时候禁止它。(后续文章会深入介绍)

嵌入层

我们定义的第一个网络层是嵌入层,这一层的作用是将词汇索引映射到低维度的词向量进行表示。它本质是一个我们从数据中学习得到的词汇向量表。

with tf.device('/cpu:0'), tf.name_scope("embedding"):
    W = tf.Variable(
        tf.random_uniform([vocab_size, embedding_size], -1.0, 1.0),
        name="W")
    self.embedded_chars = tf.nn.embedding_lookup(W, self.input_x)
    self.embedded_chars_expanded = tf.expand_dims(self.embedded_chars, -1)

在这里,我们又使用了一些新功能,让我们来学习一下它们:

  • tf.device("/cpu:0") 强制代码在CPU上面执行操作。因为默认情况下,TensorFlow会尝试将操作放在GPU上面进行运行(如果存在GPU),但是嵌入层的操作目前还不支持GPU运行,所以如果你不指定CPU进行运行,那么程序会报错。
  • tf.name_scope 创建了一个称之为"embedding"的新的名称范围,该范围将所有的操作都添加到这个"embedding"节点下面。以便在TensorBoard中获得良好的层次结构,有利于可视化。

W 是我们的嵌入矩阵,这个矩阵是我们从数据训练过程中得到的。最开始,我们使用一个随机均匀分布来进行初始化。tf.nn.embedding_lookup 创建实际的嵌入读取操作,这个嵌入操作返回的数据维度是三维张量 [None, sequence_length, embedding_size]

TensorFlow 的卷积操作 conv2d 需要一个四维的输入数据,对应的维度分别是批处理大小,宽度,高度和通道数。在我们嵌入层得到的数据中不包含通道数,所以我们需要手动添加它,所以最终的数据维度是 [None, sequence_length, embedding_size, 1]

卷积层和池化层

现在我们可以构建我们的卷积层和池化层了。请记住,我们使用的卷积核是不同尺寸的。因为每个卷积核经过卷积操作之后产生的张量是不同维度的,所有我们需要为每一个卷积核创建一层网络,最后再把这些卷积之后的觉果合并成一个大的特征向量。

pooled_outputs = []
for i, filter_size in enumerate(filter_sizes):
    with tf.name_scope("conv-maxpool-%s" % filter_size):
        # Convolution Layer
        filter_shape = [filter_size, embedding_size, 1, num_filters]
        W = tf.Variable(tf.truncated_normal(filter_shape, stddev=0.1), name="W")
        b = tf.Variable(tf.constant(0.1, shape=[num_filters]), name="b")
        conv = tf.nn.conv2d(
            self.embedded_chars_expanded,
            W,
            strides=[1, 1, 1, 1],
            padding="VALID",
            name="conv")
        # Apply nonlinearity
        h = tf.nn.relu(tf.nn.bias_add(conv, b), name="relu")
        # Max-pooling over the outputs
        pooled = tf.nn.max_pool(
            h,
            ksize=[1, sequence_length - filter_size + 1, 1, 1],
            strides=[1, 1, 1, 1],
            padding='VALID',
            name="pool")
        pooled_outputs.append(pooled)

# Combine all the pooled features
num_filters_total = num_filters * len(filter_sizes)
self.h_pool = tf.concat(3, pooled_outputs)
self.h_pool_flat = tf.reshape(self.h_pool, [-1, num_filters_total])

代码中,W 表示不同的卷积核,h 表示对经过卷积得到的输出结果进行非线性处理之后的结果。每个卷积核会覆盖整个词向量长度,但是滑动覆盖几个单词就是不同的了。VALID 填充意味着,我们的卷积核只在我们的单词上面滑动,而不填充边缘,是执行窄卷积,所有最后输出的维度是 [1, sequence_length - filter_size + 1, 1, 1] 。对经过特定卷积的输出,我们做最大池化操作,使得我们得到的张量维度是 [batch_size, 1, 1, num_filters]。这实质上就是一个特征向量,其中最后一个维度就是对应于我们的特征。一旦我们拥有了来自各个卷积核的输出向量,那么我们就可以把它们合并成一个长的特征向量,该向量的维度是 [batch_size, num_filters_total] 。在 tf.reshape 中使用 -1,就是告诉 TensorFlow 在可能的情况下,将维度进行展平。

上面部分最好花点时间看明白,去弄明白每个操作输出的维度是什么。如果你不是很了解,也可以再去参考这篇博客 Understanding Convolutional Neural Networks for NLP,获得一些灵感。下图是TensorBoard可视化的结果,你可以发现三个卷积核组成了三个不同的网络层。



Dropout层

Dropout 也许是最流行的方法来正则化卷积神经网络。Dropout 的思想非常简单,就是按照一定的概率来“禁用”一些神经元的发放。这种方法可以防止神经元共同适应一个特征,而迫使它们单独学习有用的特征。神经元激活的概率,我们从参数 dropout_keep_prob 中得到。我们在训练阶段将其设置为 0.5,在测试阶段将其设置为 1.0(即所有神经元都被激活)。

# Add dropout
with tf.name_scope("dropout"):
    self.h_drop = tf.nn.dropout(self.h_pool_flat, self.dropout_keep_prob)

分数和预测

我们使用来自池化层的特征向量(经过Dropout),然后通过全连接层,得到一个分数最高的类别。我们还可以应用softmax函数来将原始分数转换成归一化概率,但这个操作是保护会改变我们的最终预测。

with tf.name_scope("output"):
    W = tf.Variable(tf.truncated_normal([num_filters_total, num_classes], stddev=0.1), name="W")
    b = tf.Variable(tf.constant(0.1, shape=[num_classes]), name="b")
    self.scores = tf.nn.xw_plus_b(self.h_drop, W, b, name="scores")
    self.predictions = tf.argmax(self.scores, 1, name="predictions")

上面代码中,tf.nn.xw_plus_b是一个很方便的函数,实现 Wx + b 操作。

损失函数和正确率

使用我们上面求得的分数,我们可以定义损失函数。损失值是对模型所造成的误差的度量,我们的目标是最小化这个损失值。分类问题的标准损失函数是交叉熵损失函数

# Calculate mean cross-entropy loss
with tf.name_scope("loss"):
    losses = tf.nn.softmax_cross_entropy_with_logits(self.scores, self.input_y)
    self.loss = tf.reduce_mean(losses)

这里,tf.nn.softmax_cross_entropy_with_logits 是一个方便的函数,用来计算每个类别的交叉损失熵,对于我们给定的分数和输入的正确标签。然后,我们计算损失值的平均值。当然,我们也可以对它们进行求和,但是这会对不同批大小的损失值衡量非常困难,尤其是在训练阶段和测试阶段。

我们还定义了一个正确率的函数,它的作用就是在训练阶段和测试阶段来跟踪模型的性能。

# Calculate Accuracy
with tf.name_scope("accuracy"):
    correct_predictions = tf.equal(self.predictions, tf.argmax(self.input_y, 1))
    self.accuracy = tf.reduce_mean(tf.cast(correct_predictions, "float"), name="accuracy")

可视化网络

就这样,我们完成了网络的定义。完整代码可以点击这里。在TensorBoard中我们可以看到以下的大图。


训练过程

在我们编写我们网络的训练过程之前,我们需要先了解一下TensorFlow中的会话(Session)和图(Graph)的概念。如果你已经对这些概念很熟悉了,那么可以跳过这个部分。

在TensorFlow中,会话是一个图执行的环境(也就是说,图必须在会话中被启动),它包含有关的变量和队列状态。每个会话执行一个单一的图。如果你在创建变量和操作时,没有明确地使用一个会话,那么TensorFlow会创建一个当前默认会话。你可以通过在 session.as_default() 中来修改默认会话(如下)。

图(Graph)中包含各种操作和张量。你可以在程序中使用多个图,但是大多数程序都只需要一个图。你可以把一张图在多个会话中使用,但是不能在一个会话中使用多个图。TensorFlow总是会创建一个默认图,但是你也可以自己手动创建一个图,并且把它设置为默认图,就像我们下面所写的一样。显示的创建会话和图可以确保在不需要它们的时候,正确的释放资源。这是一个很好的习惯。

with tf.Graph().as_default():
    session_conf = tf.ConfigProto(
      allow_soft_placement=FLAGS.allow_soft_placement,
      log_device_placement=FLAGS.log_device_placement)
    sess = tf.Session(config=session_conf)
    with sess.as_default():
        # Code that operates on the default graph and session comes here...

allow_soft_placement 参数的设置,允许 TensorFlow 回退到特定操作的设备,如果在优先设备不存在时。比如,如果我们的代码是运行在一个GPU上面的,但是我们的代码在一个没有GPU的机器上运行了。那么,如果不使用 allow_soft_placement 参数,程序就会报错。如果设置了 log_device_placement 参数,TensorFlow 会记录它运行操作的设备(CPU或者GPU)。这对调试程序非常有用,FLAGS 是我们程序的命令行参数。

实现卷积神经网络和损失函数最小化

当我们实例化我们的 TextCNN 模型时,所有定义的变量和操作都将被放入我们创建的默认图和会话中。

cnn = TextCNN(
    sequence_length=x_train.shape[1],
    num_classes=2,
    vocab_size=len(vocabulary),
    embedding_size=FLAGS.embedding_dim,
    filter_sizes=map(int, FLAGS.filter_sizes.split(",")),
    num_filters=FLAGS.num_filters)

接下来,我们定义如何去最优化我们网络的损失函数。TensorFlow有很多内嵌的优化函数。在这里,我们使用Adam优化器。

global_step = tf.Variable(0, name="global_step", trainable=False)
optimizer = tf.train.AdamOptimizer(1e-4)
grads_and_vars = optimizer.compute_gradients(cnn.loss)
train_op = optimizer.apply_gradients(grads_and_vars, global_step=global_step)

在上述代码中,trian_op 是一个新创建的操作,我们可以运行它来对我们的参数进行梯度更新。每次执行 train_op 操作,就是一个训练步骤。TensorFlow 会自动计算出哪些变量是“可训练”的,并计算它们的梯度。通过定义 global_step 变量并将它传递给优化器,我们允许TensorFlow处理我们的训练步骤。我们每次执行 train_op 操作时,global_step 都会自动递增1。

汇总

TensorFlow有一个汇总的概念,它允许你在训练和评估阶段来跟踪和可视化各种参数。比如,你可能想要去跟踪在各个训练和评估阶段,损失值和正确值是如何变化的。当然,你还可以跟踪更加复杂的数据。例如,图层激活的直方图。汇总是一个序列化对象,我们可以使用 SummaryWriter 函数来将它们写入磁盘。

# Output directory for models and summaries
timestamp = str(int(time.time()))
out_dir = os.path.abspath(os.path.join(os.path.curdir, "runs", timestamp))
print("Writing to {}\n".format(out_dir))

# Summaries for loss and accuracy
loss_summary = tf.scalar_summary("loss", cnn.loss)
acc_summary = tf.scalar_summary("accuracy", cnn.accuracy)

# Train Summaries
train_summary_op = tf.merge_summary([loss_summary, acc_summary])
train_summary_dir = os.path.join(out_dir, "summaries", "train")
train_summary_writer = tf.train.SummaryWriter(train_summary_dir, sess.graph_def)

# Dev summaries
dev_summary_op = tf.merge_summary([loss_summary, acc_summary])
dev_summary_dir = os.path.join(out_dir, "summaries", "dev")
dev_summary_writer = tf.train.SummaryWriter(dev_summary_dir, sess.graph_def)

在这里,我们独立的去处理训练阶段和评估阶段的汇总。在我们的例子中,在训练阶段和评估阶段,我们记录的汇总数据都是一样的。但是,你可能会有一些汇总数据是只想在训练阶段进行记录的(比如,参数更新值)。tf.merge_summary 是一个方便的函数,它可以将多个汇总操作合并到一个我们可以执行的单个操作中。

检查点

在TensorFlow中,另一个你通常想要的功能是检查点(checkpointing)——保存模型的参数以备以后恢复。检查点可用于在以后的继续训练,或者提前来终止训练,从而能来选择最佳参数。检查点是使用 Saver 对象来创建的。

# Checkpointing
checkpoint_dir = os.path.abspath(os.path.join(out_dir, "checkpoints"))
checkpoint_prefix = os.path.join(checkpoint_dir, "model")
# Tensorflow assumes this directory already exists so we need to create it
if not os.path.exists(checkpoint_dir):
    os.makedirs(checkpoint_dir)
saver = tf.train.Saver(tf.all_variables())

初始化变量

在我们训练我们的模型之前,我们还需要去初始化图中的所有变量。

sess.run(tf.initialize_all_variables())

initialize_all_variables 函数是一个方便的函数,它能帮助我们去初始化所有的变量。当然你也能手动初始化你自己的参数。手动初始化是非常有用的,比如你想要去初始化你的词向量(嵌入层),用与训练好的词向量模型。

定义单个训练步骤

现在我们定义一个训练函数,用于单个训练步骤,在一批数据上进行评估,并且更新模型参数。

def train_step(x_batch, y_batch):
    """
    A single training step
    """
    feed_dict = {
      cnn.input_x: x_batch,
      cnn.input_y: y_batch,
      cnn.dropout_keep_prob: FLAGS.dropout_keep_prob
    }
    _, step, summaries, loss, accuracy = sess.run(
        [train_op, global_step, train_summary_op, cnn.loss, cnn.accuracy],
        feed_dict)
    time_str = datetime.datetime.now().isoformat()
    print("{}: step {}, loss {:g}, acc {:g}".format(time_str, step, loss, accuracy))
    train_summary_writer.add_summary(summaries, step)

feed_dict 包含了我们需要传入到网络中的数据。你必须为所有的占位符节点提供值,否则TensorFlow会报错。另一种输入数据的方式是使用队列,但这种方法超出了本次的范围,所以我们先不讨论这种方法。

接下来,我们使用 session.run 来执行我们的 train_op ,它会返回我们要求它评估的所有操作的值。注意,train_op 不返回任何东西,它只是更新我们的网络参数。最后,我们打印当前训练的损失值和正确值,并且把汇总结果保存到磁盘。请注意,如果批处理规模很小,那么损失值和模型正确值可能在不同批次之间会有很大的不同。因为我们使用了 Dropout ,所以我们的训练真确率可能会比测试正确率低一点。

我们写了一个相似的函数来评估任意数据集的损失值和真确率,比如在交叉验证数据集和整个训练集上面。本质上,这个函数和上面的函数是相同的,但是没有训练操作,它也禁用了 Dropout 。

def dev_step(x_batch, y_batch, writer=None):
    """
    Evaluates model on a dev set
    """
    feed_dict = {
      cnn.input_x: x_batch,
      cnn.input_y: y_batch,
      cnn.dropout_keep_prob: 1.0
    }
    step, summaries, loss, accuracy = sess.run(
        [global_step, dev_summary_op, cnn.loss, cnn.accuracy],
        feed_dict)
    time_str = datetime.datetime.now().isoformat()
    print("{}: step {}, loss {:g}, acc {:g}".format(time_str, step, loss, accuracy))
    if writer:
        writer.add_summary(summaries, step)

循环训练

最后,我们准备去写完整的训练过程。我们对数据集进行批次迭代操作,为每个批处理调用一次 train_step 函数,偶尔去评估一下我们的训练模型。

# Generate batches
batches = data_helpers.batch_iter(
    zip(x_train, y_train), FLAGS.batch_size, FLAGS.num_epochs)
# Training loop. For each batch...
for batch in batches:
    x_batch, y_batch = zip(*batch)
    train_step(x_batch, y_batch)
    current_step = tf.train.global_step(sess, global_step)
    if current_step % FLAGS.evaluate_every == 0:
        print("\nEvaluation:")
        dev_step(x_dev, y_dev, writer=dev_summary_writer)
        print("")
    if current_step % FLAGS.checkpoint_every == 0:
        path = saver.save(sess, checkpoint_prefix, global_step=current_step)
        print("Saved model checkpoint to {}\n".format(path))

这里,batch_iter 是一个我批处理数据的帮助函数,tr.train.global_step 是一个方便函数,它返回 global_step 的值。点击此处可以查看完整代码。

在 TensorBoard 中查看可视化结果

我们的训练脚本将汇总结果写入到输出目录,通过使用 TensorBoard 指向该目录,我们就可以可视化创建的图形和摘要。

tensorboard --logdir /PATH_TO_CODE/runs/1449760558/summaries/

使用默认参数训练我们的模型(128-dimensional embeddings, filter sizes of 3, 4 and 5, dropout of 0.5 and 128 filters per filter size) ,那么我们可以得到如下图(蓝色是训练数据,红色是10%的交叉验证数据):



这里有一些需要指出的点:

  • 我们训练的指标不是那么平滑,因为我们使用的批处理太小了。如果我们使用一个比较大的批处理(或者在整个训练集上面进行评估),那么我们将得到一个更加平滑的蓝线。
  • 交叉测试集的正确率显著低于训练集的正确率,这可能是因为网络在训练数据集上面过拟合了,也就是说我们需要更多的数据(MR数据集非常小),更强的正则化或者更小的模型参数。比如,我在最后一层的权重上面添加 L2 惩罚项,那么正确率就能达到76%,接近于原始论文中的数据。
  • 训练阶段的损失值和正确率显著低于交叉验证时,这是因为我们使用了 Dropout 。

你可以运行调试这个程序,去玩各种参数。点击这里查看完整代码。

扩展和练习

以下是一些可以帮助提高模型性能的方法:

  • 词向量用 word2vec 进行初始化。如果你要让这种方法有效,那么需要使用 300 维的词向量来进行模型的初始化工作。
  • 使用L2范数对最后一层中的权重进行约束,就像原始论文中的一样。你也可以通过定义一个新的操作来更新每次训练之后的权重值。
  • 添加L2正则项到网络中,以防止过拟合,也可以尝试增加 dropout 系数。(我的代码中已经实现了L2正则项,但是默认情况下是禁用的。)
  • 将权重更新和网络层操作的结果都保存起来,然后在 TensorBoard 中进行可视化。

本文转载自:http://www.jianshu.com/p/ed3eac3dcb39

共有 人打赏支持
AllenOR灵感
粉丝 10
博文 2139
码字总数 82983
作品 0
程序员
用TensorFlow实现物体检测的像素级分类

雷锋网(公众号:雷锋网) AI 科技评论按:本文由「图普科技」编译自Using Tensorflow Object Detection to Do Pixel Wise Classification。 最近,TensorFlow 的「物体检测 API」有了一个新功...

图普科技 ⋅ 04/14 ⋅ 0

史上最全TensorFlow学习资源汇总

来源 悦动智能(公众号ID:aibbtcom) 本篇文章将为大家总结TensorFlow纯干货学习资源,非常适合新手学习,建议大家收藏。 ▌一 、TensorFlow教程资源 1)适合初学者的TensorFlow教程和代码示...

悦动智能 ⋅ 04/12 ⋅ 0

Tensorflow快餐教程(1) - 30行代码搞定手写识别

去年买了几本讲tensorflow的书,结果今年看的时候发现有些样例代码所用的API已经过时了。看来自己维护一个保持更新的Tensorflow的教程还是有意义的。这是写这一系列的初心。 快餐教程系列希望...

lusing ⋅ 04/16 ⋅ 0

16- 深度学习之神经网络核心原理与算法-caffe&keras框架图片分类

之前我们在使用cnn做图片分类的时候使用了CIFAR-10数据集 其他框架对于CIFAR-10的图片分类是怎么做的 来与TensorFlow做对比。 Caffe Keras 安装 官方安装文档: https://github.com/IraAI/ca...

天涯明月笙 ⋅ 06/04 ⋅ 0

【干货】史上最全的Tensorflow学习资源汇总,速藏!

一 、Tensorflow教程资源: 1)适合初学者的Tensorflow教程和代码示例:(https://github.com/aymericdamien/TensorFlow-Examples)该教程不光提供了一些经典的数据集,更是从实现最简单的“Hel...

技术小能手 ⋅ 04/16 ⋅ 0

送书&优惠丨对深度学习感兴趣的你,不了解这些就太OUT了!

点击上方“程序人生”,选择“置顶公众号” 第一时间关注程序猿(媛)身边的故事 TensorFlow是什么? TensorFlow的前身是谷歌大脑(google brain)团队研发的DistBelief。自创建以来,它便被...

csdnsevenn ⋅ 05/03 ⋅ 0

有道云笔记是如何使用TensorFlow Lite的?

文 / 有道技术团队 近年来,有道技术团队在移动端实时 AI 能力的研究上,做了很多探索及应用的工作。2017 年 11 月 Google 发布 TensorFlow Lite (TFLlite) 后,有道技术团队第一时间跟进 TF...

谷歌开发者 ⋅ 04/21 ⋅ 0

入门 | TensorFlow的动态图工具Eager怎么用?这是一篇极简教程

  选自Github   作者:Madalina Buzau   机器之心编译   参与:王淑婷、泽南      去年 11 月,Google Brain 团队发布了 Eager Execution,一个由运行定义的新接口,为 TensorFl...

机器之心 ⋅ 06/14 ⋅ 0

cnn卷积神经网络及其tensorflow的一些资源汇总

ccn原理的理解 深度学习Deep Learning(01)_CNN卷积神经网络 再看CNN中的卷积 这两篇文章里推荐的资源也很好: CNN(卷积神经网络)是什么?有入门简介或文章吗? CS231n课程笔记翻译:卷积神...

firing00 ⋅ 04/13 ⋅ 0

tensorflow 获取变量&打印权值等方法

tensorflow 获取变量&打印权值等方法 在使用tensorflow中,我们常常需要获取某个变量的值,比如:打印某一层的权重,通常我们可以直接利用变量的name属性 来获取,但是当我们利用一些第三方的...

cassiepython ⋅ 01/27 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

从方法论到零售客户实践 解码阿里巴巴数据中台——2018上海云栖大会

摘要: 一、数据中台之道 6月8日,上海云栖大会进入了第二天的议程,数据中台专场论坛座无虚席,数据中台总架构师邓中华女士向在场的观众介绍了数据中台的衍生发展之道。 基于OneID、OneData...

阿里云云栖社区 ⋅ 25分钟前 ⋅ 0

Ubuntu部署django问题汇总

使用Anaconda3的Python3.6的pip安装UWSGI报错 原因是gcc版本不兼容,安装4.7并修改gccsudo apt-get install gcc-4.7sudo mv /usr/bin/gcc /usr/bin/gcc.baksudo ln -s /usr/bin/gcc-4.......

wuyaSama ⋅ 28分钟前 ⋅ 0

从方法论到零售客户实践 解码阿里巴巴数据中台——2018上海云栖大会

摘要: 一、数据中台之道 6月8日,上海云栖大会进入了第二天的议程,数据中台专场论坛座无虚席,数据中台总架构师邓中华女士向在场的观众介绍了数据中台的衍生发展之道。 基于OneID、OneData...

猫耳m ⋅ 28分钟前 ⋅ 0

Docker减肥小记

如果经常使用 docker,你会发现 docker 占用的资源膨胀很快,其中最明显也最容易被察 如何快速的清理 docker 占用的系统资源,具体点说就是删除那些无用的镜像、容器、网络和数据卷… 1、查看...

寰宇01 ⋅ 39分钟前 ⋅ 0

微信小程序中如何使用WebSocket实现长连接(含完整源码)

本文由腾讯云技术团队原创,感谢作者的分享。 1、前言 微信小程序提供了一套在微信上运行小程序的解决方案,有比较完整的框架、组件以及 API,在这个平台上面的想象空间很大。腾讯云研究了一...

JackJiang- ⋅ 47分钟前 ⋅ 0

定制库到Maven本地资源库

1.如果只有定制库的JAR文件 下载链接如下:pdf.jar 2.使用命令转换成Maven本地资源 mvn install:install-file -Dfile=/Users/manager/Downloads/clj-pdf-2.2.33.jar -DgroupId=clj-pdf -Dar......

年少爱追梦 ⋅ 51分钟前 ⋅ 0

高仿springmvc之xuchen-mvc

package org.mvc.framework.servlet; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.......

徐志 ⋅ 53分钟前 ⋅ 0

关于自定义URLStreamHandler的一次踩坑

关于自定义URLStreamHandler的一次踩坑 20180625 lambo init 说明 一般自定义实现url的协议解析.方案为实现URLStreamHandler.实现其 openConnection 就可以了, 如果我们执行 new URL("xx://...

林小宝 ⋅ 54分钟前 ⋅ 0

【SM2证书】利用BC的X509v3CertificateBuilder组装X509国密证书

演示证书文件 链接: https://pan.baidu.com/s/1ijHNnMQJj7jzW-jXEVd6Gg 密码: vfva 所需jar包 <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcpkix-jdk15on --> <dependenc......

小帅帅丶 ⋅ 55分钟前 ⋅ 0

用Calendar 实现 计算 一段时间的毫秒值

Calendar c=Calendar.getInstance();c.add(Calendar.MONTH, -1);int lastMonthMaxDay=c.getActualMaximum(Calendar.DAY_OF_MONTH);c.set(c.get(Calendar.YEAR), c.get(Calendar.MONTH)......

岸芷汀兰 ⋅ 59分钟前 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部