【NLP傻瓜式教程】手把手带你CNN文本分类(附代码)

2023-10-31

文章来源于NewBeeNLP,作者kaiyuan

写在前面

本文是对经典论文《Convolutional Neural Networks for Sentence Classification[1]》的详细复现,(应该是)基于TensorFlow 1.1以及python3.6。从数据预处理、模型搭建、模型训练预测以及可视化一条龙讲解,旨在为刚接触该领域不知道如何下手搭建网络的同学提供一个参考。废话不说直接进入主题吧

NLP中的CNN

论文中是使用的CNN框架来实现对句子的分类,积极或者消极。当然这里我们首先必须对CNN有个大概的了解,可以参考我之前的这篇【Deep learning】卷积神经网络CNN结构。目前主流来看,CNN主要是应用在computer vision领域,并且可以说由于CNN的出现,使得CV的研究与应用都有了质的飞跃。(可惜的是,目前在NLP领域还没有这种玩意儿,不知道刚出的BERT算不算)【update@20200221:算!算!算!】

目前对NLP的研究分析应用最多的就是RNN系列的框架,比如RNN,GRU,LSTM等等,再加上Attention,基本可以认为是NLP的标配套餐了。但是在文本分类问题上,相比于RNN,CNN的构建和训练更为简单和快速,并且效果也不差,所以仍然会有一些研究。

那么,CNN到底是怎么应用到NLP上的呢?

不同于CV输入的图像像素,NLP的输入是一个个句子或者文档。句子或文档在输入时经过embedding(word2vec或者Glove)会被表示成向量矩阵,其中每一行表示一个词语,行的总数是句子的长度,列的总数就是维度。例如一个包含十个词语的句子,使用了100维的embedding,最后我们就有一个输入为10x100的矩阵。

在CV中,filters是以一个patch(任意长度x任意宽度)的形式滑过遍历整个图像,但是在NLP中,filters会覆盖到所有的维度,也就是形状为 [filter_size, embed_size]。更为具体地理解可以看下图,输入为一个7x5的矩阵,filters的高度分别为2,3,4,宽度和输入矩阵一样为5。每个filter对输入矩阵进行卷积操作得到中间特征,然后通过pooling提取最大值,最终得到一个包含6个值的特征向量。

弄清楚了CNN的结构,下面就可以开始实现文本分类任务了。

数据预处理

原论文中使用了好几个数据集,这里我们只选择其中的一个——Movie Review Data from Rotten Tomatoes[2]。该数据集包括了10662个评论,其中一半positive一半negative。

在数据处理阶段,主要包括以下几个部分:

1、load file
def load_data_and_labels(positive_file, negative_file):
    #load data from files
    positive_examples = list(open(positive_file, "r", encoding='utf-8').readlines())
    positive_examples = [s.strip() for s in positive_examples]
    negative_examples = list(open(negative_file, "r", encoding='utf-8').readlines())
    negative_examples = [s.strip() for s in negative_examples]
    # Split by words
    x_text = positive_examples + negative_examples
    x_text = [clean_str(sent) for sent in x_text]
    # Generate labels
    positive_labels = [[0, 1] for _ in positive_examples]
    negative_labels = [[1, 0] for _ in negative_examples]
    y = np.concatenate([positive_labels, negative_labels], 0)
    return [x_text, y]
2、clean sentences
def clean_str(string):
    string = re.sub(r"[^A-Za-z0-9(),!?\'\`]", " ", string)
    string = re.sub(r"\'s", " \'s", string)
    string = re.sub(r"\'ve", " \'ve", string)
    string = re.sub(r"n\'t", " n\'t", string)
    string = re.sub(r"\'re", " \'re", string)
    string = re.sub(r"\'d", " \'d", string)
    string = re.sub(r"\'ll", " \'ll", string)
    string = re.sub(r",", " , ", string)
    string = re.sub(r"!", " ! ", string)
    string = re.sub(r"\(", " \( ", string)
    string = re.sub(r"\)", " \) ", string)
    string = re.sub(r"\?", " \? ", string)
    string = re.sub(r"\s{2,}", " ", string)
    return string.strip().lower()

模型实现

论文中使用的模型如下所示其中第一层为embedding layer,用于把单词映射到一组向量表示。接下去是一层卷积层,使用了多个filters,这里有3,4,5个单词一次遍历。接着是一层max-pooling layer得到了一列长特征向量,然后在dropout 之后使用softmax得出每一类的概率。

在一个CNN类中实现上述模型

class TextCNN(object):
    """
    A CNN class for sentence classification
    With a embedding layer + 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):
        """

        :param sequence_length: The length of our sentences
        :param num_classes:     Number of classes in the output layer(pos and neg)
        :param vocab_size:      The size of our vocabulary
        :param embedding_size:  The dimensionality of our embeddings.
        :param filter_sizes:    The number of words we want our convolutional filters to cover
        :param num_filters:     The number of filters per filter size
        :param l2_reg_lambda:   optional

这里再注释一下filter_sizes和num_filters。filters_sizes是指filter每次处理几个单词,num_filters是指每个尺寸的处理包含几个filter。

1. Input placeholder

tf.placeholder是tensorflow的一种占位符,与feeed_dict同时使用。在训练或者测试模型阶段,我们可以通过feed_dict来喂入输入变量。

# set placeholders for variables
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函数第一个参数是变量类型,第二个参数是变量shape,其中None表示sample的个数,第三个name参数用于指定名字。

dropout_keep_prob变量是在dropout阶段使用的,我们在训练的时候选取50%的dropout,在测试时不使用dropout。

2. Embedding layer

我们需要定义的第一个层是embedding layer,用于将词语转变成为一组向量表示。

 # embedding layer
 with tf.name_scope('embedding'):
        self.W = tf.Variable(tf.random_uniform([vocab_size, embedding_size], -1.0, 1.0), name='weight')
        self.embedded_chars = tf.nn.embedding_lookup(self.W, self.input_x)
        # TensorFlow’s convolutional conv2d operation expects a 4-dimensional tensor
        # with dimensions corresponding to batch, width, height and channel.
        self.embedded_chars_expanded = tf.expand_dims(self.embedded_chars, -1)

W 是在训练过程中学习到的参数矩阵,然后通过tf.nn.embedding_lookup来查找到与input_x相对应的向量表示。tf.nn.embedding_lookup返回的结果是一个三维向量,[None, sequence_length, embedding_size]。但是后一层的卷积层要求输入为四维向量(batch, width,height,channel)。所以我们要将结果扩展一个维度,才能符合下一层的输入。

3. Convolution and Max-Pooling Layers

在卷积层中最重要的就是filter。回顾本文的第一张图,我们一共有三种类型的filter,每种类型有两个。我们需要迭代每个filter去处理输入矩阵,将最终得到的所有结果合并为一个大的特征向量。

# conv + max-pooling for each filter
pooled_outputs = []
for i, filter_size in enumerate(filter_sizes):
    with tf.name_scope('conv-maxpool-%s' % filter_size):
        # conv 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')
        # activation
        h = tf.nn.relu(tf.nn.bias_add(conv, b), name='relu')
        # max pooling
        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 fratures
num_filters_total = num_filters * len(filter_sizes)
self.h_pool = tf.concat(pooled_outputs, 3)  # why 3?
self.h_pool_flat = tf.reshape(self.h_pool, [-1, num_filters_total])

这里W 就是filter矩阵, tf.nn.conv2d是tensorflow的卷积操作函数,其中几个参数包括

  • strides表示每一次filter滑动的距离,它总是一个四维向量,而且首位和末尾必定要是1[1, width, height, 1]

  • padding有两种取值:VALID和SAME。

    • VALID是指不在输入矩阵周围填充0,最后得到的output的尺寸小于input;

    • SAME是指在输入矩阵周围填充0,最后得到output的尺寸和input一样;

这里我们使用的是‘VALID’,所以output的尺寸为[1, sequence_length - filter_size + 1, 1, 1]

接下去是一层max-pooling,pooling比较好理解,就是选出其中最大的一个。经过这一层的output尺寸为 [batch_size, 1, 1, num_filters]

4. Dropout layer

这个比较好理解,就是为了防止模型的过拟合,设置了一个神经元激活的概率。每次在dropout层设置一定概率使部分神经元失效, 每次失效的神经元都不一样,所以也可以认为是一种bagging的效果。

# dropout
with tf.name_scope('dropout'):
    self.h_drop = tf.nn.dropout(self.h_pool_flat, self.dropout_keep_prob)
5. Scores and Predictions

我们可以通过对上述得到的特征进行运算得到每个分类的分数score,并且可以通过softmax将score转化成概率分布,选取其中概率最大的一个作为最后的prediction

#score and prediction
with tf.name_scope("output"):
    W = tf.get_variable('W', shape=[num_filters_total, num_classes],
                        initializer = tf.contrib.layers.xavier_initializer())
    b = tf.Variable(tf.constant(0.1, shape=[num_classes]), name='b')
    l2_loss += tf.nn.l2_loss(W)
    l2_loss += tf.nn.l2_loss(b)
    self.score = tf.nn.xw_plus_b(self.h_drop, W, b, name='scores')
    self.prediction = tf.argmax(self.score, 1, name='prediction')
6. Loss and Accuracy

通过score我们可以计算得出模型的loss,而我们训练的目的就是最小化这个loss。对于分类问题,最常用的损失函数是cross-entropy 损失

 # mean cross-entropy loss
with tf.name_scope('loss'):
    losses = tf.nn.softmax_cross_entropy_with_logits(logits=self.score, labels=self.input_y)
    self.loss = tf.reduce_mean(losses) + l2_reg_lambda * l2_loss

为了在训练过程中实时观测训练情况,我们可以定义一个准确率

# accuracy
with tf.name_scope('accuracy'):
    correct_predictions = tf.equal(self.prediction, tf.argmax(self.input_y, 1))
    self.accuracy = tf.reduce_mean(tf.cast(correct_predictions, 'float'), name='accuracy')

到目前为止,我们的模型框架已经搭建完成,可以使用Tensorboardd来瞧一瞧到底是个啥样

模型训练

接下去我们就要开始使用影评数据来训练网络啦。

创建图和session

对于Tensorflow有两个重要的概念:Graph和Session。

  • Session会话可以理解为一个计算的环境,所有的operation只有在session中才能返回结果;

  • Graph图就可以理解为上面那个图片,在图里面包含了所有要用到的操作operations和张量tensors。

PS:在一个项目中可以使用多个graph,不过我们一般习惯只用一个就行。同时,在一个graph中可以有多个session,但是在一个session中不能有多个graph。

with tf.Graph().as_default():
    session_conf = tf.ConfigProto(
        # allows TensorFlow to fall back on a device with a certain operation implemented
        allow_soft_placement= FLAGS.allow_soft_placement,
        # allows TensorFlow log on which devices (CPU or GPU) it places operations
        log_device_placement=FLAGS.log_device_placement
    )
    sess = tf.Session(config=session_conf)
Initialize CNN
cnn = TextCNN(sequence_length=x_train.shape[1],
              num_classes=y_train.shape[1],
              vocab_size= len(vocab_processor.vocabulary_),
              embedding_size=FLAGS.embedding_dim,
              filter_sizes= list(map(int, FLAGS.filter_sizes.split(','))),
              num_filters= FLAGS.num_filters,
              l2_reg_lambda= FLAGS.l2_reg_lambda)
global_step = tf.Variable(0, name='global_step', trainable=False)
optimizer = tf.train.AdamOptimizer(1e-3)
grads_and_vars = optimizer.compute_gradients(cnn.loss)
train_op = optimizer.apply_gradients(grads_and_vars, global_step=global_step)

这里train_op的作用就是更新参数,每运行一次train_op,global_step都会增加1。

Summaries

Tensorflow有一个特别实用的操作,summary,它可以记录训练时参数或者其他变量的变化情况并可视化到tensorboard。使用tf.summary.FileWriter()函数可以将summaries写入到硬盘保存到本地。

# visualise gradient
grad_summaries = []
for g, v in grads_and_vars:
    if g is not None:
        grad_hist_summary = tf.summary.histogram('{}/grad/hist'.format(v.name),g)
        sparsity_summary = tf.summary.scalar('{}/grad/sparsity'.format(v.name), tf.nn.zero_fraction(g))
        grad_summaries.append(grad_hist_summary)
        grad_summaries.append(sparsity_summary)
grad_summaries_merged = tf.summary.merge(grad_summaries)

# output dir for models and summaries
timestamp = str(time.time())
out_dir = os.path.abspath(os.path.join(os.path.curdir, 'run', timestamp))
print('Writing to {} \n'.format(out_dir))

# summaries for loss and accuracy
loss_summary = tf.summary.scalar('loss', cnn.loss)
accuracy_summary = tf.summary.scalar('accuracy', cnn.accuracy)

# train summaries
train_summary_op = tf.summary.merge([loss_summary, accuracy_summary])
train_summary_dir = os.path.join(out_dir, 'summaries', 'train')
train_summary_writer = tf.summary.FileWriter(train_summary_dir, sess.graph)

# dev summaries
dev_summary_op = tf.summary.merge([loss_summary, accuracy_summary])
dev_summary_dir = os.path.join(out_dir, 'summaries', 'dev')
dev_summary_writer = tf.summary.FileWriter(dev_summary_dir, sess.graph)
Checkpointing

checkpointing的作用就是可以保存每个阶段训练模型的参数,然后我们可以根据准确率来选取最好的一组参数。

checkpoint_dir = os.path.abspath(os.path.join(out_dir, 'checkpoints'))
checkpoint_prefix = os.path.join(checkpoint_dir, 'model')
if not os.path.exists(checkpoint_dir):
    os.makedirs(checkpoint_dir)
saver = tf.train.Saver(tf.global_variables(), max_to_keep=FLAGS.num_checkpoints)
Initializing the variables

在开始训练之前,我们通常会需要初始化所有的变量。一般使用 tf.global_variables_initializer()就可以了。

Defining a single training step

我们可以定义一个单步训练的函数,使用一个batch的数据来更新模型的参数

def train_step(x_batch, y_batch):
    """
    A single training step
    :param x_batch:
    :param y_batch:
    :return:
    """
    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=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就是我们前面提到的同placeholder一起使用的。必须在feed_dict中给出所有placeholder节点的值,否则程序就会报错。

接着使用sess.run()运行前面定义的操作,最终可以得到每一步的损失、准确率这些信息。

类似地我们定义一个函数在验证集数据上看看模型的准确率等

def dev_step(x_batch, y_batch, writer=None):
    """
    Evaluate model on a dev set
    Disable dropout
    :param x_batch:
    :param y_batch:
    :param writer:
    :return:
    """
    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=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)
Training loop

前面都定义好了以后就可以开始我们的训练了。我们每次调用train_step函数批量的训练数据并保存:

# generate batches
batches = data_process.batch_iter(list(zip(x_train, y_train)), FLAGS.batch_size, FLAGS.num_epochs)
# training loop
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('\n Evaluation:')
        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('Save model checkpoint to {} \n'.format(path))

最后输出的效果大概是这样的

Visualizing Results

我们可以在代码目录下打开终端输入以下代码来启动浏览器的tensorboard:

tensorboard --logdir /runs/xxxxxx/summaries

小结

当然这只是一个利用CNN进行NLP分类任务(文本分类,情感分析等)的baseline,可以看出准确率并不是很高,后续还有很多可以优化的地方,包括使用pre-trained的Word2vec向量、加上L2正则化等等。

完整代码可以在公众号后台回复"CNN2014"获取。

本文参考资料

[1]

Convolutional Neural Networks for Sentence Classification: https://arxiv.org/abs/1408.5882

[2]

Movie Review Data from Rotten Tomatoes: http://www.cs.cornell.edu/people/pabo/movie-review-data/

END -

往期精彩回顾




适合初学者入门人工智能的路线及资料下载机器学习在线手册深度学习在线手册AI基础下载(pdf更新到25集)备注:加入本站微信群或者qq群,请回复“加群”获取一折本站知识星球优惠券,请回复“知识星球”喜欢文章,点个在看
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【NLP傻瓜式教程】手把手带你CNN文本分类(附代码) 的相关文章

  • RS485在切换收发状态的时候收到0x00

    介绍一下测试背景 我使用单片机的TTL232 通过MAX485芯片转成RS485协议 但是遇到一个问题 MAX485芯片在从发送状态切换到接收状态的时候会收到一个0x00 很显然这是一个 假 数据 并不是真实接收到的数据 这个0x00着实有
  • C++中namespace detail或namespace internal的使用

    在很多开源代码中偶尔会使用名字为 detail 或 internal 的命名空间 如OpenCV的modules目录中 有些文件中使用了namespace detail 有些文件中使用了namespace internal 名为detail
  • Ceph 存储池命令 以及 数据压缩

    文章目录 一 存储池操作 1 1 常用命令 1 2 删除存储池 1 3 存储池配额 1 4 存储池可用参数 二 存储池快照 2 1 创建快照 2 2 验证快照 2 3 回滚快照 2 4 删除快照 三 数据压缩 3 1 启用压缩并指定压缩算法
  • Oracle ——删除表中重复记录

    为了方便 假设表名为Tbl 表中有三列col1 col2 col3 其中col1 col2是主键 并且 col1 col2上加了索引重复数据删除 1 通过创建临时表 把数据先导入到一个临时表中 然后删除原表的数据 再把数据导回原表 SQL语
  • 【PBR系列三】BRDF方程及渲染方程

    本文核心知识主要参照 现代计算机图形学入门 闫令琪课程课件PPT 后续光线追踪系列知识也源于此处 一 BRDF方程 通过上一部分所有辐射度量学各种概念的定义之后 我们可以从这样一个角度理解光线的反射 如下图所示 一个点 微分面积元 在接受到
  • 怎样安装NPM离线包

    因为一些 你懂的 原因 工作环境无法直接使用npm install联网安装npm包 稍微花了点时间研究了一下 Mark下来 有机会看源码再补充 最佳方案 别浪费时间了 最好还是在网络环境下把所需的包全部安装好 再想办法搬回来 尽管可以一个一
  • VMware Workstation 在此主机上不支持嵌套虚拟化。报错一秒解决

    VMware Workstation 在此主机上不支持嵌套虚拟化 这是由于VMware与Windows11自带的Hyper V冲突所导致的 简单的解决方法是 将虚拟机设置中的CPU虚拟化取消勾选 如图所示
  • Ubuntu 安装Google浏览器

    Ubuntu自带的浏览器是火狐浏览器 使用的时候多多少少有些不方便 这里安装Googel浏览器 下载 可以到 Ubuntu chrome去下载安装包 安装 首先到下载的根目录 cd Downloads sudo dpkg i google
  • Mybatis1.2 查询所有数据

    1 2 查询所有数据 1 2 1 编写接口方法 1 2 2 编写SQL语句 1 2 3 编写测试方法 1 2 4 起别名解决上述问题 1 2 5 使用resultMap解决上述问题 1 2 6 小结 如上图所示就页面上展示的数据 而这些数据
  • http 请求头大小写的问题

    如果是默认消息头名称 消息头格式已经固定 即便输入的大小写有误 也会给你翻译成默认的写法 如果自己定义的 会自动给你翻译成小写 所以传参数的名称都用小写字母即可 否则可能取不到值 比如encryptedString会取不到值 使用encry
  • 【华为OD机试真题】最短木板长度(python)100%通过率 超详细代码注释 代码解读

    华为OD机试真题 2022 2023 真题目录 点这里 华为OD机试真题 信号发射和接收 试读 点这里 华为OD机试真题 租车骑绿道 试读 点这里 最短木板长度 时间限制 1s空间限制 256MB限定语言 不限 题目描述 小明有 n 块木板
  • 在windows下C++使用Native wifi API获取SSID和连接信息

    在linux下获取当前连接的信息很是轻松的 但是在windows下相对比较复杂 虽然可以考虑使用cmd命令获取网卡的信息并分析出当前连接的SSID 但是对于网络环境比较复杂的情况下其实我们同样可以使用Native wifi API获取目前的
  • linphone-android for mac编译过程记录

    本文记录linphone andoroid在mac上的编译过程 在这里做下记录 希望对大家有所帮助 如有疑问发评论即可 环境搭建 代码下载 git clone git git linphone org linphone android gi
  • 阿里云学生服务器配置及免费学生机领取攻略

    阿里云学生服务器优惠活动从云翼计划升级为开发者成长计划 现在学生服务器活动为高校学生在家实践计划 学生用户群可以免费领取阿里云学生服务器 如果购买特价服务器只需要新用户即可 不需要学生认证即可享受优惠价 阿里云百科来详细说下阿里云学生服务器
  • 二、从C到C++(二) 引用、引用常见用途、指针和引用区别、const引用

    一 引用类型 引用 像一个自动能被编译器逆向引用的常量型指针 它通常用于函数的参数表中和函数的返回值 但也可以独立使用 比如 int x int r x 使用引用的一些规则 当引用被创建时 它必须被初始化 指针则可以在任何时候被初始化 一旦
  • 对主流编程语言的认识

    主流编程语言的认识 语言 用途 C 操作系统 嵌入式开发 C 游戏 图形图像 桌面软件 服务器 C 桌面软件 服务器 JAVA JAVA SE 桌面软件 Android JAVA EE 企业级应用 web开发 服务器 JAVA ME 手机应
  • el-upload上传视频获取视频宽高、时长信息(多文件、单文件)

  • frp安装

    安装包下载 Releases fatedier frp github com 一 服务端配置 上传安装包至可连外网服务器解压 tar xzfv frp 0 48 0 linux amd64 tar gz 进入解压文件夹修改frps ini文
  • Ajax是什么以及Ajax交互原理(详,图文并茂,原理篇)

    一 Ajax技术与原理 1 1 Ajax简介 Ajax Asynchronous JavaScript and XML 翻译成人话就是 异步的 javascript 和 XML 相结合的一种技术 需要澄清的是 Ajax不是新的编程语言 而是
  • 11、Restoring Vision in Adverse Weather Conditions with Patch-Based Denoising Diffusion Models

    简介 官网 https github com IGITUGraz WeatherDiffusion 在图像恢复中使用它们的一个主要障碍是它们的架构约束 禁止尺寸无关的图像恢复 而图像恢复基准和现实世界的问题由不同尺寸的图像组成 基于去噪扩散

随机推荐

  • 研一寒假C++复习笔记--深拷贝和浅拷贝代码实例

    目录 1 深拷贝和浅拷贝的基础概念 2 浅拷贝的代码实例 3 深拷贝代码实例 4 参考 1 深拷贝和浅拷贝的基础概念 浅拷贝 简单的赋值拷贝操作 深拷贝 在堆区重新申请空间 进行拷贝操作 2 浅拷贝的代码实例 include
  • idea2021.1运行时报:Cannot start compiler The output path is not specified for module StringTest 错误解决

    错因分析 根据提示可以知道 idea没有指定编译的输出路径 解决方法 直接点击提示下面的蓝色字体 Configure 如果Configure不能点击 可以通过 File gt Project Structure 打开 然后会弹出窗口
  • 运用Microsoft.DirectX.DirectSound和Microsoft.DirectX实现简单的录音功能

    1 首先要使用Microsoft DirectX DirectSound和Microsoft DirectX这两个dll进行录音 需要先安装microsoft directx 9 0cz这个组件 百度云盘下载地址 http pan baid
  • win11的C/C++环境配置——基于MinGW-W64 GCC-8.1.0

    首先给出MinGW W64 GCC 8 1 0的下载地址 MinGW8 1 0 Win11下的C C 环境配置 下载MinGW W64 GCC 8 1 0 添加bin文件和include文件到path变量中 测试 下载MinGW W64 G
  • 6.deep_residual_network

    import torch import torch nn as nn import torchvision import torchvision transforms as transforms device torch device cu
  • VMware虚拟机桥接配置,访问局域网虚拟机

    目的 同一局域网 两台主机的虚拟机互通 背景 家里有两台电脑 一台台式 一台手提 想让他们的虚拟机可以直接通信而不是添加端口 以小米路由器为例 确认ip所在网段 机器信息 台式机 192 168 91 192 gt 虚拟机 192 168
  • CEP的设计模式--构建模块

    一 事件 EVENT 是由schema来定义的 是事件属性的元组 二 流 STREAM 事件流 time ordered sequence of event 是基于时间的事件序列 append only 不能移除事件 只能追加 unboun
  • vue3+ts项目打包后的本地访问

    注意 打包之后不可直接点击html访问 需要给项目安装本地服务 1 安装servenpm i g serve 2 打包项目npm run build 生成dist文件夹 3 本地访问serve dist 运行service dist之后的控
  • WebService 代码创建E9流程

    下载CXF http cxf apache org download html 生成客户端代码 tar zxvf apache cxf 3 2 7 tar gz cd apache cxf 3 2 7 bin wsdl2java clien
  • 定义类数组

    在java中 可以类为基本对象来定义一个数组 也就是直接以一个class作为一个类型 同时里面还有属性 编写学生类 包含姓名 学号 成绩三个属性 题目要求 1 为学生类添加构造函数给每个成员属性赋值 使用this关键字 2 为学生添加toS
  • Centos7部署轻量级自动化运维工具pssh (亲测)

    下载pssh安装包 root localhost wget https files pythonhosted org packages 60 9a 8035af3a7d3d1617ae2c7c174efa4f154e5bf9c24b36b6
  • js中数组的sort()方法及原理

    定义与用法 sort 方法用于对数组的元素进行排序 语法 arrayObject sort sortby 注意 sortby必须是函数 规定排序顺序 可选参数 返回值 对数组的引用 请注意 数组在原数组上进行排序 不生成副本 说明及原理 如
  • matlab打开出现桌面错误,手把手为您win10系统笔记本运行Matlab软件弹出已停止工作错误窗...

    今天小编分享一下win10系统笔记本运行Matlab软件弹出已停止工作错误窗口问题的处理方法 在操作win10电脑的过程中常常不知道怎么去解决win10系统笔记本运行Matlab软件弹出已停止工作错误窗口的问题 有什么好的方法去处理win1
  • C++ string类

    目录 1 为什么要学习string类 1 1 C语言中的字符串 1 2 两个面试题 暂不做讲解 2 标准库中的string类 2 1 string类 了解 2 2 string类的常用接口说明 注意下面我只讲解最常用的接口 1 string
  • webstorm+小程序相配合来开发小程序

    前言 webstorm可以安装的一个小程序插件 wechat miniprogram plugin 来实现小程序语法的高亮 并识别 rpx 这种小程序专有单位 还可以实现跟开发者工具中一些类似的操作功能 注意事项 1 小程序的根目录下的pr
  • 类对象数组初始化(三种方法)

    参考自 More Effective C 中文版 类对象数组初始化参考自 More Effective C 中文版 类对象数组初始化 如有一个如下类 class EquipmentPiece private int IDNumber pub
  • Python中tkinter库的menu的使用(制作菜单栏)

    import tkinter as tk wd tk Tk wd title 11 wd geometry 300x300 l tk Label wd text bg yellow pack 先载入对象 类似父类 嵌套对象 menubar
  • Nginx四层代理和七层代理的区别

    4层是指传输层的TCP UDP协议 7层是指应用层的HTTP协议 代理原理 4层代理 使用NAT Network Address Translation 技术 即网络地址转换 即请求进来的时候 nginx只修改数据包里面的目标IP 源IP
  • 浅谈密码破译

    关于密码破译 今天见到一篇文章 读来心中甚是激动 特记录在案 目录 密码破译 1 两种方式 2 双重验证系统2FA 3 密码登录的常见方式 3 1 基于 存储密码 的密码登录步骤 3 2 基于 密码散列 的密码登录步骤 4 暴力破解散列 密
  • 【NLP傻瓜式教程】手把手带你CNN文本分类(附代码)

    文章来源于NewBeeNLP 作者kaiyuan 写在前面 本文是对经典论文 Convolutional Neural Networks for Sentence Classification 1 的详细复现 应该是 基于TensorFlo