file

00 前言

欢迎学习《昇腾行业应用案例》的“基于 Bert 模型实现文本分类”实验。在本实验中,您将学习如何使用利用 NLP (natural language processing) 领域的AI模型来构建一个端到端的文本系统,并使用开源数据集进行效果验证。为此,我们将使用昇腾的AI硬件以及CANN等软件产品。

学习目标 <br> 本教程旨在帮助读者深入理解和掌握基于自然语言处理(NLP)技术的文本分类方法,包括:

  • 文本分类的基本概念、应用场景以及技术原理
  • 掌握文本预处理的流程和方法,如使用 Tokenizer 类进行文本分词、编码和截断等操作
  • 学会运用预训练的 BERT 模型进行文本分类任务

目录 <br> 本实验分为四个部分。在第一部分中,我们将介绍本案例的场景,阐述文本分类在各个领域的广泛应用场景,展示其实际价值和重要性。在第二部分中,我们将介绍本案例的端到端解决方案,深入讲解文本分类的技术原理,包括自然语言处理基础、关键工具与库的使用,以及模型的选择和构建方法,如 BERT 模型的推理过程。接下来,在第三部分中,我们将指导您完成解决方案对应的代码实现。在最后一部分,我们给出了一些测试题,帮助您巩固所学知识,加深对文本分类技术的理解和应用能力。

  1. 场景介绍
  2. 解决方案
  3. 动手实验
  4. 课后习题

JupyterLab

在本实操实验中,我们将使用 JupyterLab 管理我们的环境。JupyterLab 界面是一个控制面板,可供您访问交互式 iPython Notebook、所用环境的文件夹结构,以及用于进入 Ubuntu 操作系统的终端窗口,只需要点击菜单栏的小三角就可以运行代码。

尝试执行下方单元中的一条简单的 print(打印)语句。

# DO NOT CHANGE THIS CELL
# activate this cell by selecting it with the mouse or arrow keys then use the keyboard shortcut [Shift+Enter] to execute
print('This is just a simple print statement')
This is just a simple print statement

01 场景介绍

在当今数字化信息爆炸的时代,文本分类技术的应用场景无处不在且至关重要。

在新闻媒体行业,每天产生的海量新闻稿件需要快速准确地分类到不同的主题类别,如政治、经济、文化、科技、体育、娱乐等,以便读者能够迅速找到自己感兴趣的内容,同时也方便媒体机构进行内容管理和推荐。

社交媒体平台上,用户发布的海量帖子和评论需要进行情感分析和主题分类,企业可以借此了解公众对其产品或品牌的看法,及时发现潜在的危机,并制定相应的营销策略。 电子商务领域,客户对商品的评价和咨询信息对于商家改进产品和服务至关重要,通过文本分类技术,商家可以快速将这些文本分类,以便针对性地处理客户问题和反馈,提高客户满意度和忠诚度。

此外,在学术研究领域,研究人员需要从海量的文献中筛选出与自己研究课题相关的文献,文本分类技术可以根据文献的标题、摘要等信息将其分类到不同的学科领域和研究方向,大大提高了科研效率。

在政府部门,文本分类技术也被广泛应用于舆情监测、政策文件分类等工作中,有助于政府及时了解社会动态和公众需求,制定更加科学合理的政策。

02 解决方案

file

文本分类的核心在于将文本的语义信息转化为计算机能够理解和处理的形式,进而实现对文本类别的准确判断。这涉及到文本表示学习分类模型构建两个关键方面。

2.1 文本表示学习

其目标是将文本转换为数值向量,以便计算机进行后续的处理和分析。早期的文本表示方法如词袋模型(Bag-of-Words),将文本看作是单词的集合,忽略单词的顺序和语法结构,通过统计单词在文本中出现的频率来构建向量表示。这种方法简单直观,但丢失了大量的语义信息。随着技术的发展,词向量模型如 Word2Vec 和 GloVe 应运而生,它们通过在大规模语料上的无监督学习,将每个单词映射到一个低维的向量空间中,使得语义相近的单词在向量空间中的距离相近,从而更好地捕捉了单词之间的语义关系。近年来,基于深度学习的预训练模型如 BERT(Bidirectional Encoder Representations from Transformers)、GPT(Generative Pretrained Transformer)等取得了巨大的成功。这些模型利用 Transformer 架构的强大编码能力,在大规模语料上进行预训练,学习到了丰富的语言知识和语义表示,能够根据上下文生成高质量的文本向量表示,为文本分类任务提供了更强大的特征提取能力。

Tokenizer 类及其相关类:Tokenizer 类是本教程中用于文本分词和编码的关键类,它能够将文本分割成单个字符(tokens),并将 tokens 转换为对应的索引,以适应模型的输入要求。Tokenizer 类提供了丰富的功能,包括分词方法(如 _tokenize 方法通过一系列规则将文本分割成单词或子词)、打包方法(_pack 方法将分词后的标记进行打包,并生成相应的索引和段标识)、编码方法(encode 方法将文本转换为模型输入所需的索引序列和段标识序列)等。这些类共同构成了文本预处理的核心组件,为将原始文本数据转换为适合模型输入的格式提供了关键支持。

file

2.2 分类模型构建

在获得文本的向量表示后,需要使用分类模型对其进行类别预测。常见的分类算法包括传统的机器学习算法如朴素贝叶斯(Naive Bayes)、支持向量机(Support Vector Machine)等,这些算法基于统计学原理和特征工程,在一些简单的文本分类任务上能够取得较好的效果。然而,随着文本数据的复杂性增加,深度学习模型逐渐成为文本分类的主流方法。深度学习模型通过构建多层神经网络结构,能够自动从文本数据中学习复杂的特征和模式,避免了繁琐的手工特征工程。例如,卷积神经网络(CNN)可以通过卷积层提取文本中的局部特征,然后通过池化层进行特征聚合,最后通过全连接层进行分类预测;循环神经网络(RNN)及其变体(如 LSTM 和 GRU)能够处理文本的序列信息,捕捉单词之间的依赖关系,适用于文本序列较长且上下文信息较为重要的场景;Transformer 架构则通过多头注意力机制(Multi-Head Attention),能够同时关注文本中的不同位置信息,进一步提升了模型对文本语义的理解和表达能力,在大规模文本分类任务中表现出卓越的性能。

file

BERT(Bidirectional Encoder Representations from Transformers)模型是一种基于 Transformer 架构的预训练语言模型,在自然语言处理任务中表现出色,包括文本分类。以下是 BERT 模型推理的一般步骤:

  • 加载预训练模型
  • 文本预处理:使用分词器对输入文本进行分词、编码和截断等预处理操作,将文本转换为模型能够接受的输入格式,通常是一个包含输入 ID、注意力掩码和段 ID 的字典
  • 模型推理:将预处理后的文本输入到 BERT 模型中,得到模型的输出。模型输出通常是一个包含多个隐藏层表示的张量,可以根据具体任务需求选择合适的输出层进行后续处理
  • 后处理:根据模型的输出进行后处理,例如对于文本分类任务,可以将模型输出的隐藏层表示通过一个全连接层和 softmax 函数转换为各类别的概率分布,然后选择概率最大的类别作为预测结果

03 动手实验

3.1 实验准备

数据集准备

  1. 构建词汇表(vocab.txt):词汇表是文本分类模型的基石,它将文本中的单词或字符映射到唯一的整数索引,使得模型能够理解和处理文本数据。本实验使用的词汇表可以在gitee链接下载。构建词汇表的过程通常包括以下步骤:
  • 收集涵盖目标领域的大量文本数据,可以来自公开的数据集、网络爬虫获取的文本、企业内部的文档等。例如,对于一个旨在对新闻文章进行分类的模型,需要收集来自不同新闻网站、不同主题的新闻稿件,确保词汇表能够覆盖各种领域的词汇。
  • 对收集到的文本数据进行分词处理,可以使用现有的分词工具如 jieba(中文分词)或 nltk(英文分词)等,将文本分割成单词或字符序列。 统计每个单词或字符在文本数据中的出现频率,选取高频且具有代表性的词汇作为词汇表的候选词。通常会设置一个频率阈值,只保留出现频率高于该阈值的词汇,以避免词汇表过大导致模型训练效率降低和过拟合问题。
  • 为每个选定的词汇分配一个唯一的整数索引,并将词汇及其对应的索引写入 vocab.txt 文件,每行一个词汇及其索引,格式为 “词汇 索引”。例如:乜 0, 九 1, 乞 2, 也 3, 习 4, ...
  • 此外,还会添加一些特殊的标记,如 [PAD](用于文本填充)、[UNK](表示未知词汇)、[CLS](用于分类任务的起始标记)、[SEP](用于分隔不同的文本片段)等,并为它们分配固定的索引。
  1. 测试样本:本实验使用的词汇表可以在gitee链接下载,里面包含了 “体育", "健康", "军事", "教育", "汽车" 等5个类别的新闻。

模型权重

本实验使用了tensorflow的 Bert 模型进行文本分类,权重来源于gitee社区,下载后的文件名为 bert_text_classification.pb

很好,接下来让我们正式进入代码操作的步骤!

3.2 文本预处理模块

如2.2章节所述,为了把文本信息转换成 AI 模型能够处理的格式,我们需要进行预处理,首先需要对一段文本进行 tokenize 操作,也就是“分词”操作,然后再把每个词转成整数索引。记录词和整数之间对应关系的文本叫做 vocab.txt ,这个文件把绝大多数中文字符都包含了,此外还包含了一些特殊字符,如 [CLS][UNK][SEP]等,他们的功能分别是定义用于表示分类任务起始的标记、定义用于表示未知单词的标记、定义用于分隔不同文本部分的标记。

我们可以用一个字典把 vocab.txt 里面的内容保存下来:

import os
import codecs
token_dict = {}
if os.path.exists("data/vocab.txt") != True:
    print("The vocab.txt does not exist, please input the right path!")
    exit()
with codecs.open("data/vocab.txt", 'r', 'utf-8') as reader:
    for line in reader:
        token = line.strip()
        token_dict[token] = len(token_dict)

接下来,我们创建 Tokenizer 类,这个类主要包含初始化函数 __init__、端到端编码函数 encode() 以及3个内部函数。

class Tokenizer(object):
    """
    这个类的主要作用是将文本分割为整数索引,便于后续自然语言处理任务使用。
    """
    def __init__(self,
                 token_dict,
                 token_cls='[CLS]',
                 token_sep='[SEP]',
                 token_unk='[UNK]',
                 pad_index=0,
                 cased=False):
        """
        初始化Tokenizer类。

        :param token_dict: 一个字典,用于将标记(tokens)映射到对应的索引(indices),是文本到索引转换的关键映射表。
        :param token_cls: 代表分类任务起始的标记,通常用于模型输入时标识开头。
        :param token_sep: 代表分隔不同文本部分的标记,比如在处理句子对任务中用于分隔两个句子。
        :param token_unk: 代表未知单词的标记,当遇到不在词汇表(token_dict)中的单词时使用。
        :param pad_index: 用于填充的索引值,例如在将不同长度的文本序列处理为等长时使用。
        :param cased: 布尔值,用于指示是否保留文本的原始大小写情况,False表示将文本统一处理为小写等情况。
        """
        self._token_dict = token_dict
        # 创建一个反向字典,方便从索引查找对应的标记,键值对互换
        self._token_dict_inv = {v: k for k, v in token_dict.items()}
        self._token_cls = token_cls
        self._token_sep = token_sep
        self._token_unk = token_unk
        self._pad_index = pad_index
        self._cased = cased

    def _pack(self, first_tokens, second_tokens=None):
        """
        将多个句子合并成1个。

        :param first_tokens: 第一个文本对应的标记列表。
        :param second_tokens: 可选参数,第二个文本对应的标记列表,如果存在第二个文本需要一起打包时传入。
        :return: 返回打包后的标记列表,以及第一个文本部分的长度和第二个文本部分(如果有)的长度。
        """
        # 先添加分类起始标记,再添加第一个文本的标记,最后添加分隔标记
        first_packed_tokens = [self._token_cls] + first_tokens + [self._token_sep]
        if second_tokens is not None:
            second_packed_tokens = second_tokens + [self._token_sep]
            # 返回合并后的打包标记列表,以及两部分文本标记列表的长度
            return first_packed_tokens + second_packed_tokens, len(first_packed_tokens), len(second_packed_tokens)
        else:
            return first_packed_tokens, len(first_packed_tokens), 0

    def _convert_tokens_to_ids(self, tokens):
        """
        将词组列表转换为对应的索引列表,使用词汇表(token_dict)进行映射,如果标记不在词汇表中则使用未知标记的索引。

        :param tokens: 要转换的标记列表。
        :return: 对应的索引列表。
        """
        unk_id = self._token_dict.get(self._token_unk)
        return [self._token_dict.get(token, unk_id) for token in tokens]

    def _tokenize(self, content):
        """
        将一个文本进行分词。

        :param tokens: 要转换的标记列表。
        :return: 对应的索引列表。
        """
        R = []
        for c in content:
            if c in self._token_dict:
                R.append(c)
            else:
                # The remaining characters are [UNK]
                R.append('[UNK]')
        return R

    def encode(self, first, second=None, max_len=None):
        """
        将输入的文本(可以是单个文本或两个文本)进行编码,转换为索引序列以及对应的段标识(segment_ids)。

        :param first: 第一个文本内容。
        :param second: 可选参数,第二个文本内容,如果有则一起进行编码处理。
        :param max_len: 最大允许的长度,如果文本超过该长度会进行截断处理。
        :return: 包含文本索引序列(token_ids)和段标识序列(segment_ids)的元组。
        """
        # 把句子进行分词
        first_tokens = self._tokenize(first)
        second_tokens = self._tokenize(second) if second is not None else None
        tokens, first_len, second_len = self._pack(first_tokens, second_tokens)

        # 把词列表转成索引
        token_ids = self._convert_tokens_to_ids(tokens)
        segment_ids = [0] * first_len + [1] * second_len

        if max_len is not None:
            pad_len = max_len - first_len - second_len
            token_ids += [self._pad_index] * pad_len
            segment_ids += [0] * pad_len

        # 返回分词结果
        return token_ids, segment_ids

此外,考虑到我们使用的模型的输入长度是 300 ,我们还需要对分词结果进行一个预处理:

import numpy as np
def preprocess(input_text):
    """
    tokenizer text to ID. Fill with 0 if the text  is not long than maxlen
    """
    tokenizer = Tokenizer(token_dict)

    # tokenize
    maxlen = 298
    input_text = input_text[:maxlen]
    x1, x2 = tokenizer.encode(first=input_text)

    # if the length of the text is less than tensor_length, padding 0
    tensor_length = 300
    x1 = x1 + [0] * (tensor_length - len(x1)) if len(x1) < tensor_length else x1
    x2 = x2 + [0] * (tensor_length - len(x2)) if len(x2) < tensor_length else x2

    x1 = np.ascontiguousarray(x1, dtype='float32')
    x2 = np.ascontiguousarray(x2, dtype='float32')

    x1 = np.expand_dims(x1, 0)
    x2 = np.expand_dims(x2, 0)
    return x1, x2

好了,现在我们来测试一下我们的预处理函数功能是否完好:

sample_text = "深圳金威队今天下午将在主场对阵青岛中能队。这场保级对手之间的对决对双方而言都非常关键。目前,中超的保级形势非常复杂,第六名只比第十五名多五分,从现在开始,每场比赛都非常重要。深足目前排名中超倒数第五,少赛一场的青岛队则倒数第四。由于青岛队只比排倒数第一的重庆队多出两分,他们非常希望在深圳获得救命三分。深足主力后卫忻峰和青岛队主力后卫刘俊威本轮都将停赛。两支进攻乏力的队伍,本轮同时面对后防的空虚。对阵实力一般的青岛队,深足主教练王宝山希望李毅与丹尼尔能找到状态,力争在比赛中撕破对手的防线。青岛队主教练殷铁生则认为,他们近九个赛季在深圳的战绩是八战八负,这个耻辱的纪录必须在他手中终结。殷铁生希望青岛队全力以赴,争取改写在深圳体育场不胜的历史。青岛队的球员则没那么乐观,他们对深圳的闷热天气有所忌惮,只希望在这里以不败的结果离开。"
X1, X2 = preprocess(sample_text)
print(X1.shape, X2.shape)
(1, 300) (1, 300)

3.3 构建推理模型

接下来,我们需要构建一个模型类,用来处理推理请求。首先,我们需要把3.1章节中提到的 pb 模型转成昇腾硬件支持的 om 格式:

# atc --model=bert_text_classification.pb --framework=3 --input_format="ND" --output=bert_text_classification --input_shape="input_1:1,300;input_2:1,300" --out_nodes=dense_1/Softmax:0 --soc_version=芯片型号 --op_select_implmode="high_precision"

然后像昇腾案例(一)里面一样,如下构建模型类:

import acl

ACL_MEM_MALLOC_HUGE_FIRST = 0
ACL_MEMCPY_HOST_TO_DEVICE = 1
ACL_MEMCPY_DEVICE_TO_HOST = 2

class OmModel:
    def __init__(self, model_path):
     # 初始化函数
     self.device_id = 5
    
     # step1: 初始化
     ret = acl.init()
     # 指定运算的Device
     ret = acl.rt.set_device(self.device_id)
    
     # step2: 加载模型,本示例为pfld模型
     # 加载离线模型文件,返回标识模型的ID
     self.model_id, ret = acl.mdl.load_from_file(model_path)
     # 创建空白模型描述信息,获取模型描述信息的指针地址
     self.model_desc = acl.mdl.create_desc()
     # 通过模型的ID,将模型的描述信息填充到model_desc
     ret = acl.mdl.get_desc(self.model_desc, self.model_id)
    
     # step3:创建输入输出数据集
     # 创建输入数据集
     self.input_dataset, self.input_data = self.prepare_dataset('input')
     # 创建输出数据集
     self.output_dataset, self.output_data = self.prepare_dataset('output')

    def prepare_dataset(self, io_type):
     # 准备数据集
     if io_type == "input":
         # 获得模型输入的个数
         io_num = acl.mdl.get_num_inputs(self.model_desc)
         acl_mdl_get_size_by_index = acl.mdl.get_input_size_by_index
     else:
         # 获得模型输出的个数
         io_num = acl.mdl.get_num_outputs(self.model_desc)
         acl_mdl_get_size_by_index = acl.mdl.get_output_size_by_index
     # 创建aclmdlDataset类型的数据,描述模型推理的输入。
     dataset = acl.mdl.create_dataset()
     datas = []
     for i in range(io_num):
         # 获取所需的buffer内存大小
         buffer_size = acl_mdl_get_size_by_index(self.model_desc, i)
         # 申请buffer内存
         buffer, ret = acl.rt.malloc(buffer_size, ACL_MEM_MALLOC_HUGE_FIRST)
         # 从内存创建buffer数据
         data_buffer = acl.create_data_buffer(buffer, buffer_size)
         # 将buffer数据添加到数据集
         _, ret = acl.mdl.add_dataset_buffer(dataset, data_buffer)
         datas.append({"buffer": buffer, "data": data_buffer, "size": buffer_size})
     return dataset, datas

    def forward(self, inputs):
     # 执行推理任务
     # 遍历所有输入,拷贝到对应的buffer内存中
     input_num = len(inputs)
     for i in range(input_num):
         bytes_data = inputs[i].tobytes()
         bytes_ptr = acl.util.bytes_to_ptr(bytes_data)
         # 将图片数据从Host传输到Device。
         ret = acl.rt.memcpy(self.input_data[i]["buffer"],   # 目标地址 device
                             self.input_data[i]["size"],     # 目标地址大小
                             bytes_ptr,                      # 源地址 host
                             len(bytes_data),                # 源地址大小
                             ACL_MEMCPY_HOST_TO_DEVICE)      # 模式:从host到device
     # 执行模型推理。
     ret = acl.mdl.execute(self.model_id, self.input_dataset, self.output_dataset)
     # 处理模型推理的输出数据,输出top5置信度的类别编号。
     inference_result = []
     for i, item in enumerate(self.output_data):
         buffer_host, ret = acl.rt.malloc_host(self.output_data[i]["size"])
         # 将推理输出数据从Device传输到Host。
         ret = acl.rt.memcpy(buffer_host,                    # 目标地址 host
                             self.output_data[i]["size"],    # 目标地址大小
                             self.output_data[i]["buffer"],  # 源地址 device
                             self.output_data[i]["size"],    # 源地址大小
                             ACL_MEMCPY_DEVICE_TO_HOST)      # 模式:从device到host
         # 从内存地址获取bytes对象
         bytes_out = acl.util.ptr_to_bytes(buffer_host, self.output_data[i]["size"])
         # 按照float32格式将数据转为numpy数组
         data = np.frombuffer(bytes_out, dtype=np.float32)
         inference_result.append(data)
     return inference_result  # 取第二个输出,也就是坐标点

    def __del__(self):
     # 析构函数 按照初始化资源的相反顺序释放资源。
     # 销毁输入输出数据集
     for dataset in [self.input_data, self.output_data]:
         while dataset:
             item = dataset.pop()
             ret = acl.destroy_data_buffer(item["data"])    # 销毁buffer数据
             ret = acl.rt.free(item["buffer"])              # 释放buffer内存
     ret = acl.mdl.destroy_dataset(self.input_dataset)      # 销毁输入数据集
     ret = acl.mdl.destroy_dataset(self.output_dataset)     # 销毁输出数据集
     # 销毁模型描述
     ret = acl.mdl.destroy_desc(self.model_desc)
     # 卸载模型
     ret = acl.mdl.unload(self.model_id)
     # 释放device
     ret = acl.rt.reset_device(self.device_id)
     # acl去初始化
     ret = acl.finalize()

我们来测试一下模型的功能是否正常:

# 该模型支持5个分类标签
classification_bales = ["体育", "健康", "军事", "教育", "汽车"]
# load model
points_detect_om_model_path = "./bert_text_classification.om"
points_detect_om_model = OmModel(points_detect_om_model_path)
results = points_detect_om_model.forward([X1, X2])[0]

# get data from infer_result
label = classification_bales[np.argmax(results)]
print(label)
体育

3.4 端到端推理流程

准备好了数据预处理函数和模型之后,我们就可以批量测试样本数据了:

# read the input text
if os.path.exists("data/sample.txt") != True:
    print("The sample.txt does not exist, please input the right path!")
    exit()
if os.path.getsize("data/sample.txt") == 0:
    print("The sample.txt content is null, please input the right text!")
    exit()
sample_text = open("data/sample.txt", "r")

for text in sample_text:
    # preprocess the data
    X1, X2 = preprocess(text)
    results = points_detect_om_model.forward([X1, X2])[0]
    # get data from infer_result
    label = classification_bales[np.argmax(results)]
    # print result
    print("Original text: %sPrediction label: %s \n" % (text, label))
Original text: 深圳金威队今天下午将在主场对阵青岛中能队。这场保级对手之间的对决对双方而言都非常关键。目前,中超的保级形势非常复杂,第六名只比第十五名多五分,从现在开始,每场比赛都非常重要。深足目前排名中超倒数第五,少赛一场的青岛队则倒数第四。由于青岛队只比排倒数第一的重庆队多出两分,他们非常希望在深圳获得救命三分。深足主力后卫忻峰和青岛队主力后卫刘俊威本轮都将停赛。两支进攻乏力的队伍,本轮同时面对后防的空虚。对阵实力一般的青岛队,深足主教练王宝山希望李毅与丹尼尔能找到状态,力争在比赛中撕破对手的防线。青岛队主教练殷铁生则认为,他们近九个赛季在深圳的战绩是八战八负,这个耻辱的纪录必须在他手中终结。殷铁生希望青岛队全力以赴,争取改写在深圳体育场不胜的历史。青岛队的球员则没那么乐观,他们对深圳的闷热天气有所忌惮,只希望在这里以不败的结果离开。
Prediction label: 体育 

Original text: 今天下午,沈阳金德和长春亚泰队将在五里河相遇。在这两支球队中沈阳籍球员居多,因此这场比赛实际也将是一场“沈阳内战”。库夫曼去年执教金德时,曾率队与长春亚泰队进行过一场教学比赛,当时金德队以1:0战胜对手,但是比赛过程是亚泰队占据绝对优势。这场德比教学赛进行得相当火爆,长春亚泰队两名外援均骨折。本来,亚泰队还准备回访沈阳,考虑到比赛火药味十足,最终亚泰取消了回访计划。此番在中超遭遇亚泰队,库夫曼最为头痛锋线人选,普科在上一场与辽足比赛不慎领到红牌今天不能出场。目前库夫曼手里仅剩下陈涛和班古拉两名前锋可用。好在中场大将许博停赛解禁,可以粉墨登场,在周二与预备队比赛里,许博在中场表现抢眼,这也让库夫曼吃了定心丸,这样沈阳金德队就可以组成相对完整的中后场。在看了长春亚泰与武汉光谷队的比赛录像后,库夫曼认为对手实力并不像升班马,他们的水准应该在中超位于中上游,王栋、杜震宇和卡巴雷罗等人是重点防范对象。库夫曼也知道“内战”胜负的意义,没有轻言要战胜对手,只表示金德目标应该定位在保平争胜,争取“东北三大战役”保持金身不破。昨天下午,金德和亚泰两队均到五里河体育场进行了赛前训练,从训练中可以看出,金德队强调的是短传渗透,以地面进攻为主。而亚泰则是依靠球员的良好身体素质,以长传冲吊为主,这种打法很有冲击力,看来亚泰看到了金德后防线球员年轻,身体略显单薄的弱点,准备依靠超强的冲击力来挑战金德。
Prediction label: 体育 

Original text: 主持人:现在再谈一下乳腺癌的治疗,在乳腺癌的治疗中放射治疗应该是很大的一部分,现在网友对放射治疗原理,在肿瘤(专题访谈咨询)治疗中的运用,以及所处的地位不是很了解,现在就请王维虎教授给大家介绍一下放射治疗在肿瘤治疗中的一些作用。王维虎:肿瘤医院肿瘤放射治疗科副主任医师王维虎:简单地说,放射治疗就是用X线进行肿瘤治疗的方法,我们大家都比较了解的X线主要用于肿瘤的诊断,实际上是能量比较低的X射线。另外一方面,肿瘤的放射治疗,就是用高能量的X线进行肿瘤的治疗。具体到乳腺癌的放疗,应该是乳腺癌三大治疗手段之一,手术治疗、化疗,另外就是放射治疗,所以应该在乳腺癌的治疗当中扮演着一个很重要的角色。我概括地说一下乳腺癌的放射治疗主要包括这样几个方面:第一,乳腺癌保留乳房术后的放射治疗。第二,乳腺癌的根治或者改良根治术以后放射治疗。第三,晚期乳腺癌。就是指乳腺侵犯了皮肤、侵犯了胸肌,比如出现了内乳淋巴腺转移,这部分的放射治疗。第四,转移性的,比如病人出现了骨转移或者脑转移,这方面的治疗,这些方面都有广泛的应用。这几个方面其中应该说现在目前应用最为广泛的就是乳腺癌保乳术后治疗、改良根治术以后的放射治疗。在这儿我想说的是乳腺癌保乳术后的放疗治疗。随着社会发展,乳腺癌发病有年轻化的趋势,很多人希望不仅要治好这个肿瘤,还希望能很好的治疗。保乳术的治疗要求有几个方面:第一,乳腺的肿瘤要小于4到5公分;第二,这个肿瘤应该是局限性的纤维钙化;第三,既然要保乳就要有一个好的美容效果,要求切除以后乳腺的外型不要有很大的影响;第四,考虑到美容的效果,要在乳晕以外的区域。第五,不能有胶原疾病。另外,我们还有一个很重要的原则,病人必须要自愿接受这个治疗,这是一个适应症,适应症的范围也在扩大。保乳手术在我们国内推广的比较慢,随着这个技术的不断运用,一些适应症在扩大,现在比如说浸润性小叶癌就可以做保乳手术。现在做化疗以后,如果肿瘤大于4到5公分放疗以后缩小的也可以做保乳术。如果这个肿瘤没有侵犯到乳晕的话,我们照样可以做保乳术。另外就是淋巴结转移,如果个数大于4、5个的也可以做这个手术。尽管很多情况可以做保乳术,但实际上也有很多的晋级症,下面的情况是不能考虑做保乳术的。比如在不同的象限,有2个到2个以上的病变,或者弥漫性的纤维钙化,就是多方肿瘤,可能2到3个象限上有肿瘤是不可以做保乳术的。另外,要切元干净。意思就是说切完以后如果还有肉眼可见的肿瘤是不可以做保乳术的。当然,接受完放疗的还可以做。另外,我总结一下目前保乳术的疗效。第一,从疗效的角度来讲保乳术跟既往我们所做的改良或者根治术以后疗效是相同的,这个毫无疑问,已经有很多随机分组等等证实了这一点。另外,有的做好了美容效果是很好的。很多人提到疗效,复发率根据大众的研究,局部和区域的复发率还是小于10%的,就是说这10%的病人即便再做改良根治术,效果也是很好的。
Prediction label: 健康 

Original text: 今年江西省普通高考考生志愿填报方法有变,即三本和一专、二专院校志愿填报改为网上填报。提前本科、一本、二本、艺术提前专科院校志愿填报继续采用纸质填报。记者21日获悉,目前各批次志愿填报时间已确定。6月10日至16日填报提前本科、一本、二本、艺术提前专科院校志愿;7月26日至28日填报三本院校、专科一批、专科二批院校志愿。与此同时,江西省高招办组织的高校招生网络电话咨询会也将在6月10日至13日和7月25日至26日期间举行。(记者:黄小路)(来源:信息日报)
Prediction label: 教育 

Original text: 因受到国家公布的新消费税税率的影响。近期,进口克莱斯勒&#8226;300C和大捷龙的销售价格有所上调。据记者了解,此次调价涉及到的克莱斯勒车型只有以上两个国内正规进口的型号,其它非正规进口到国内的车型暂时没有涉及到。由于在售车型的排量较大,所以受消费税的影响比较明显。以下是价格调整后,代理商处的报价:从上表我们可以清楚的看到,克莱斯勒除了300C5.7排量的车型涨幅较高,达6万元外,其他车型的涨幅相对不是很大,均在2万元。作为克莱斯勒品牌最经典的“字母系列”的最新车型,克莱斯勒&#8226;300C在04年6月北京车展一露面,就令许多车迷心驰神往。修长的发动机罩、简短的面板、动感的轮廓以及18英寸车轮,无一不展现了克莱斯勒&#8226;300C经典的造型比例。饱满雄壮的车头、张扬的方格状前脸,充满60年代美式大型轿车的复古风味。克莱斯勒&#8226;300C的每根线条、每个角度和每个比例都体现了内外的和谐统一。无论是它的专利“龟甲壳”式内饰设计还是其经典的HEMI引擎都让人印象深刻。克莱斯勒&#8226;大捷龙不断推陈出新,创新的标杆被一再提高。厢式旅行车上首创的Stow‘nGo座椅及内部空间变幻系统不但可以使第二排和第三排座椅折叠后完全收入地板之内,更为使用者在座椅处于竖直状态时提供了达340升的超大储物空间。从2座到7座的座椅组合可以在不到30秒的时间内通过单手操作,毫不费力地实现。为消费者提供了无与伦比的便利性、多功能性和装载功能。克莱斯勒&#8226;300C和大捷龙凭借自身与众不同的优势,进入国内后销售情况一直看好。此次克莱斯勒&#8226;300C和大捷龙的调价,会不会对自身的销量造成影响,只有交给市场来解答了。
Prediction label: 汽车 

3.5 软件依赖

本实验的依赖软件版本信息如下:

  1. Python:为了方便开发者进行学习,本课程采用Python代码实现,您可以在服务器上安装一个Conda,用于创建Python环境,本实验使用的是 python 3.10
  2. numpy: 开源的Python科学计算库,用于进行大规模数值和矩阵运算,本实验使用的是 1.23.0 版本;
  3. CANN(Compute Architecture for Neural Networks):Ascend芯片的使能软件,本实验使用的是 8.0.rc2 版本

04 课后习题

收集自己感兴趣领域的文本数据,如电影评论、科技文章、体育赛事报道等,构建一个特定领域的文本分类模型。对该领域的文本特点进行分析,针对性地选择合适的模型和预处理方法,并评估模型在实际应用中的效果。通过这个过程,深入了解特定领域文本分类的需求和解决方案,提高解决实际问题的能力。

本文由博客一文多发平台 OpenWrite 发布!