Advertisement

【文本分类】TextCNN的实现

阅读量:

模型

在这里插入图片描述
论文可以在这里找到Convolutional Neural Networks for Sentence Classification
后面的实现参考文本分类实战(二)—— textCNN 模型
因为用的自己的数据集,所以在此基础上做了一点点改动

代码

复制代码
    import os
    import csv
    #import time
    #import datatime
    import random
    import json
    
    from collections import Counter
    from math import sqrt
    
    import gensim
    import pandas as pd
    import numpy as np
    import tensorflow as tf
    #from sklearn.metrics import roc_auc_score,accuray_score,precision,recall_score #导入评价指标
    
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-16/V4Xs5ohEn8RuKtYaO3UvMwGzm0Il.png)
参数设置
复制代码
    #配置参数
    #训练参数
    class TrainingConfig(object):
    epoches=10
    evaluateEvery=1000
    checkpointEvery=1000
    learningRate=0.001
    #模型参数
    class ModelConfig(object):
    embeddingSize=300
    numFilters=300
    
    filterSizes=[2,3,4,5]
    dropoutKeepProb=0.5
    l2RegLambda=0.0
    
    class Config(object):
    sequenceLength=100
    batchSize=16
    
    trainSource='./data/train_data.csv'
    devSource='./data/val_data.csv'
    testSource='./data/test_data.csv'
    
    stopWordSource='./data/stopsword.txt'
    
    numClasses=44
    rate=0.8
    training=TrainingConfig()
    model=ModelConfig()
    #实例化对象
    config=Config()
    
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-16/GQifNw8PpnRF2TyMUtD1h9OBWmjx.png)
取数据的方式

我理解这部分,就是你如何从自己的数据读出数据,并处理成你模型能接受的样子,简单来说,就是你处于数据的类。
我的数据是这样的清洗后是这样的,一共是44个类别,属于多分类问题
在这里插入图片描述

复制代码
    class Dataset(object):
    def __init__(self, config):
        self.config = config
        self._trainSource = config.trainSource
        self._devSource = config.devSource
        self._testSource = config.testSource
    
        self._stopWordSource = config.stopWordSource
    
        self._sequenceLength = config.sequenceLength
        self._embeddingSize = config.model.embeddingSize
        self._batchSize = config.batchSize
        self._rate = config.rate
    
        self._stopWordDict = {}
    
        self.trainSentences = []
        self.trainLabels = []
    
        self.evalSentences = []
        self.evalLabels = []
    
        self.wordEmbedding = None
    
        self.labelList = []
    
    def _readData(self,filePath):
        #读数据的方法
        lines=open(filePath,encoding='utf-8').read().split('\n')
        sentences=''
        labels=''
        for i in range(len(lines)-1):
            item=lines[i].split('\t')
            labels+=str(item[0])
            labels+='\n'
            sentences+=str(item[1])
            sentences+='\n'
        labels = labels.strip().split('\n')
        sentences = sentences.strip().split('\n')
        return sentences,labels
    
    def _labelToIndex(self,labels,label2idx):
        #将标签转化成索引
    
        labelIds=[label2idx[label] for label in labels]
        return labelIds
    
    def _wordToIndex(self,sentences,word2idx):
        #将词转换成索引
        sentenceIds=[[word2idx.get(item, word2idx["UNK"]) for item in sentence] for sentence in sentences]
        return sentenceIds
    
    def _dealDate(self,x,y,word2idx):
        #补全或者截取句子的长度
        sentences=[]
        for sentence in x:
            if len(sentence) >= self._sequenceLength:
                sentences.append(sentence[:self._sequenceLength]) #截断过长的
            else:
                sentences.append(sentence+[word2idx["PAD"]]*(self._sequenceLength - len(sentence))) #补长
    
    
        Sentences=np.array(sentences,dtype="int64")
        Labels = np.array(y, dtype="float32")
    
        return Sentences, Labels
    
    def _genVocabulary(self,sentences,labels):
        #生成词向量 词汇-索引映射字典
        allWords = [word for sentence in sentences for word in sentence]
    
        #取掉停用词
        subWords = [word for word in allWords if word not in self.stopWordDict]
        wordCount = Counter(subWords)  # 统计词频
        sortWordCount = sorted(wordCount.items(), key=lambda x: x[1], reverse=True)
        #按照词频数排序
    
        # 去除低频词
        words = [item[0] for item in sortWordCount if item[1] >= 5]
    
        vocab, wordEmbedding = self._getWordEmbedding(words)
        self.wordEmbedding = wordEmbedding  #word-embedding的映射
    
        word2idx= dict(zip(vocab, list(range(len(vocab))))) #词表  word-id的映射
    
    
        uniqueLabel = list(set(labels))
        #print(uniqueLabel)
        label2idx = dict(zip(uniqueLabel, list(range(len(uniqueLabel))))) #标签表  label-id的映射
        self.labelList = list(range(len(uniqueLabel)))
    
        # 将词汇-索引映射表保存为json数据,之后做inference时直接加载来处理数据
        with open("./data/word2idx.json", "w", encoding="utf-8") as f:
            json.dump(word2idx, f)
    
        with open("./data/label2idx.json", "w", encoding="utf-8") as f:
            json.dump(label2idx, f)
    
        return word2idx, label2idx
    
    def _getWordEmbedding(self,words):
        #按照我们数据集建立的词表从训练好的word2vec提取出词向量
        vocab=[]
        wordEmbedding=[]
    
        # 添加 "pad" 和 "UNK",
        vocab.append("PAD")
        vocab.append("UNK")
        wordEmbedding.append(np.zeros(self._embeddingSize))
        wordEmbedding.append(np.random.randn(self._embeddingSize))
    
        #加载之前下载训练好的词向量表
        wordVec = gensim.models.KeyedVectors.load_word2vec_format("./data/sgns.wiki.word", binary=False)
    
        for word in words:
            try:
                vector = wordVec.wv[word]
                vocab.append(word)
                wordEmbedding.append(vector)
            except:
                print(word + "不存在于词向量中")
    
        return vocab, np.array(wordEmbedding)
    
    def _readStopWord(self, stopWordPath):
        """
        读取停用词
        """
        with open(stopWordPath, "r") as f:
            stopWords = f.read()
            stopWordList = stopWords.splitlines()
            # 将停用词用列表的形式生成,之后查找停用词时会比较快
            self.stopWordDict = dict(zip(stopWordList, list(range(len(stopWordList)))))
    
    def dataGen(self):
        #初始化
        #加载停用词
        self._readStopWord(self._stopWordSource)
    
        # 初始化数据集
        trainSentences1, trainLabels1=self._readData(self._trainSource)
        evalSentences1, evalLabels1=self._readData((self._devSource))
    
        sentences=trainSentences1+evalSentences1
        labels=trainLabels1+evalLabels1
        #print(type(labels))
    
        # 初始化词汇-索引映射表和词向量矩阵
        word2idx, label2idx = self._genVocabulary(sentences, labels)
    
        # 将训练集和验证集标签和句子数值化
        trainlabelIds = self._labelToIndex(trainLabels1, label2idx)
        trainsentenceIds = self._wordToIndex(trainSentences1, word2idx)
    
        evallabelIds = self._labelToIndex(evalLabels1, label2idx)
        evalsentenceIds = self._wordToIndex(evalSentences1, word2idx)
    
        # 补全或截取训练集和测试集
        trainSentences, trainLabels= self._dealDate(trainsentenceIds, trainlabelIds, word2idx)
        evalSentences, evalLabels = self._dealDate(evalsentenceIds, evallabelIds, word2idx)
    
        self.trainSentences = trainSentences
        self.trainLabels = trainLabels
       
       可以打印几条看看结果
        self.evalSentences = evalSentences
        self.evalLabels = evalLabels
        #print(evalLabels)
        #print(evalSentences[1])
        print(evalSentences[0])
        print(evalLabels[0])
    
    
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-16/18IjW7AT3OtD9p5HmiRqGuneYa2x.png)
复制代码
    data = Dataset(config)
    data.dataGen()
    
    

这里是用的训练好的word2vec的词向量
后,生成word2id.json和label2id.json文件
在这里插入图片描述

生成输入模型的batch数据
复制代码
    #生成batch数据集,用生成器的方式输出
    #采用生成器的形式向模型输入batch数据集,(生成器可以避免将所有的数据加入到内存中)
    def nextBatch(x,y,batchSize):
    prem=np.arange(len(x))
    np.random.shuffle(prem) #打乱顺序
    #打乱数据集,若是同一个batch反复出现。模型可能会学习到,所以要打乱
    x=x[prem]
    y=y[prem]
    
    numBatches = len(x) // batchSize
    #整除
    
    for i in range(numBatches):#遍历num batch
        start=i*batchSize
        end=start+batchSize
        batchX=np.array(x[start:end],dtype='int64')
        batchY = np.array(y[start: end], dtype="float32")
    
        yield batchX, batchY
    
    
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-16/pYqxeLmk0IrajiM3y8DU5F6lgW7T.png)

【注意】 这里有一步是需要打乱训练集中的数据,因为若是同一个batch反复出现。模型可能会学习到,所以要打乱。

模型结构
复制代码
    #构建模型
    class TextCNN(object):
    #用于文本分类
    def __init__(self,config,wordEmbedding):
        #定义模型的输入
        self.inputX=tf.placeholder(tf.int32,[None,config.sequenceLength],name='inputX')
        self.inputY=tf.placeholder(tf.int32,[None],name='inputY')
    
        self.dropoutKeepProb=tf.placeholder(tf.float32,name='dropoutKeepProb')
    
        #定义l2损失,正则项
        l2Loss=tf.constant(0.0)
    
        #词嵌入层
        with tf.name_scope('embedding'):
            """
            tf.name_scope()命名空间的实际作用
            在某个tf.name_scope()指定的区域中定义的所有对象及各种操作,
            他们的“name”属性上会增加该命名区的区域名,用以区别对象属于哪个区域
            """
            #利用预训练的词向量初始化词嵌入矩阵
            self.W=tf.Variable(tf.cast(wordEmbedding,dtype=tf.float32,name='word2vec'),name='W')
            #tf.cast数据类型转换
            #利用词嵌入矩阵将输入的数据中的词转换成词向量,维度[batch_size, sequence_length, embedding_size]
            self.embeddedWords=tf.nn.embedding_lookup(self.W,self.inputX)
            #卷积的输入是思维[batch_size, width, height, channel],因此需要增加维度,用tf.expand_dims来增大维度
            #增加了最后一维[batch_size, seq_len, embedding_size, channel]
            self.embeddedWordsExpanded=tf.expand_dims(self.embeddedWords,-1)
    
        #创建卷积和池化
        pooledOutputs=[]
        #有三种size的filter 2,3, 4, 5,textCNN是个多通道单层卷积的模型,可以看作三个单层的卷积模型的融合
        for i,filterSize in enumerate(config.model.filterSizes):
            with tf.name_scope('conv-maxpool-%s'%filterSize):
                #卷积层,卷积核尺寸为filterSize * embeddingSize,卷积核的个数为numFilters
                #初始化权重矩阵和偏置
                filterShape=[filterSize,config.model.embeddingSize,1,config.model.numFilters]
                #tf.truncated_normal()截断的产生正态分布的随机数,即随机数与均值的差值若大于两倍的标准差,则重新生成
                W=tf.Variable(tf.truncated_normal(filterShape,stddev=0.1),name='W')
                b=tf.Variable(tf.constant(0.1,shape=[config.model.numFilters]),name='b')
                conv=tf.nn.conv2d(
                    self.embeddedWordsExpanded,
                    W,
                    #CNN中的卷积核,它要求是一个Tensor,
                    #具有[filter_height, filter_width, in_channels, out_channels]这样的shape,
                    # 具体含义是[卷积核的高度,卷积核的宽度,图像通道数,卷积核个数],
                    # 要求类型与参数input相同,有一个地方需要注意,第三维in_channels,就是参数input的第四维
                    strides=[1,1,1,1],
                    #卷积时在图像每一维的步长,这是一个一维的向量,长度4
                    padding='VALID',
                    name='conv'
                )
    
                #relu函数
                h=tf.nn.relu(tf.nn.bias_add(conv,b),name='relu')
                #池化层,最大池化,池化是卷积后的序列取一个最大值
                pooled=tf.nn.max_pool(
                    h,
                    ksize=[1,config.sequenceLength-filterSize+1,1,1],
                    #池化窗口的大小,取一个四维向量,一般是[1, height, width, 1],
                    # 因为我们不想在batch和channels上做池化,所以这两个维度设为了1
                    strides=[1,1,1,1],
                    padding='VALID',
                    name='pool'
                )
                #将四种size的filter的输出一起加到列表中
                pooledOutputs.append(pooled)
           
        #得到cnn网络的输出长度
        numFiltersTotal=config.model.numFilters*len(config.model.filterSizes) #总卷积核数目
        #池化后的维度不变,按照最后的维度channel来concat
        self.hPool=tf.concat(pooledOutputs,3)
        #摊平成二维的数据输入到全连接层
        self.hPoolFlat=tf.reshape(self.hPool,[-1,numFiltersTotal])
    
        #dropout
        with tf.name_scope('dropout'):
            self.hDrop=tf.nn.dropout(self.hPoolFlat,self.dropoutKeepProb)
    
        #全连接层的输出
        with tf.name_scope('output'):
            outputW=tf.get_variable(
                'outputW',
                shape=[numFiltersTotal,config.numClasses],
                initializer=tf.contrib.layers.xavier_initializer()
                ##用于初始化权重的初始化程序 “Xavier” 。这个初始化器是用来保持每一层的梯度大小都差不多相同。
            )
            outputB=tf.Variable(tf.constant(0.1,shape=[config.numClasses]),name='outputB')
            l2Loss+=tf.nn.l2_loss(outputW)
            l2Loss+=tf.nn.l2_loss(outputB)
            self.logits=tf.nn.xw_plus_b(self.hDrop,outputW,outputB,name='logits')
            #shape=[-1,numFiltersTotal][numFiltersTotal,config.numClasses]=[-1,numClasses]
            #多分类用softmax
            self.pro=tf.nn.softmax(self.logits)
            self.predictions=tf.argmax(self.pro,axis=-1,name='predictions')
            #返回最大的那个数值所在的下标,predictions返回的是最大概率所属于的标签ID
    
            print(self.predictions)
            create__file('predictions',self.predictions)
            #把prediction保存在文档中
            #os.makedirs('./result/predictions.txt')
            #with open('./result/predictions.txt', "w", encoding="utf-8")as w:
                #content=''
                #for prediction in predictions:# 把预测的答案写入
                    #content+=str(prediction)
                    #content+='\n'
                #w.write(str(content))
            #w.close()
    
            with tf.name_scope('loss'):
                losses=tf.nn.sparse_softmax_cross_entropy_with_logits(logits=self.logits,labels=self.inputY)
                #计算交叉熵  原因是logits和labels在使用时有labels应该少一维的限制。
                #logits应该是batch×classes的一个矩阵,classes为类别数量labels应该是长batch的一个数组
                self.loss=tf.reduce_mean(losses)+config.model.l2RegLambda*l2Loss
    
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-16/zD6TB1kMNcsqSmZhxeE2HtYrpW9U.png)

【补上】:在动手的时候,有很多疑惑,找了一些解答得非常清晰明了的博客解答
交叉熵函数的选择:Tensorflow入门——分类问题cross_entropy的选择
损失函数的计算:损失函数 - 交叉熵损失函数
为什么要加上weight_decay,什么情况用:l2RegLambda的经验设定
初始参数会决定模型训练的好坏,很重要:tensorflow的几种参数初始化方法
Xavier:牛逼的初始化xavier(tensorflow)
变量作用域:TENSORFLOW变量作用域(VARIABLE SCOPE)

评价指标

这部分没什么好说的

复制代码
    #定义各类性能指标
    def mean(item:list) -> float:
    """
    计算列表中元素的平均值
    :param item: 列表对象
    :return:
    """
    res=sum(item)/len(item) if len(item)>0 else 0
    return res
    
    def accuracy(pred_y,true_y):
    """
    计算二分类或多分类的准确率
    :param pred_y: 预测结果
    :param true_y: 真实结果
    :return:
    """
    if isinstance(pred_y[0],list):
        pred_y=[item[0] for item in pred_y]
    corr=0
    for i in range(len(pred_y)):
        if pred_y[i]==true_y[i]:
            corr+=1
    acc=corr/len(pred_y) if len(pred_y)>0 else 0
    return acc
    
    def binary_precision(pred_y,true_y,positive=1):
    """
    二分类的精确率计算
    对于预测为正的样本中有多少是真正的正例
    :param pre_y: 预测结果
    :param true_y:真实的结果
    :param positive: 正例的索引表示
    :return:
    """
    corr=0
    pred_corr=0
    for i in range(len(pred_y)):
        if pred_y[i]==positive:
            pred_corr+=1
            if pred_y[i]==true_y[i]:
                corr+=1
    prec=corr/pred_corr if pred_corr>0 else 0
    return prec
    def binary_recall(pred_y,true_y,positive=1):
    """
    二分类的召回率
    样本中的正例有多少是预测正确的
    :param pred_y: 预测结果
    :param true_y: 真实结果
    :param positive:正例的索引表示
    :return:
    """
    corr=0
    true_corr=0
    for i in range(len(pred_y)):
        if true_y[i]==positive:
            true_corr+=1
            if pred_y[i]==true_y[i]:
                corr+=1
    rec=corr/true_corr if true_corr>0 else 0
    return rec
    
    def binary_f_beta(pred_y,true_y,beta=1.0,positive=1):
    """
    二分类的F1值
    :param pred_y: 预测结果
    :param true_y: 真实结果
    :param beta: beta值
    :param positive: 正例的索引值
    :return:
    """
    precision=binary_precision(pred_y,true_y,positive)
    recall=binary_recall(pred_y,true_y,positive)
    try:
        f_b=(1+beta*beta)*precision*recall/(beta*beta*precision+recall)
        #beta=0 计算的是f1分数
        #beta=1,F2分数认为召回率的重要程度是精确率的2倍
    except:
        f_b=0
    return f_b
    
    
    def multi_precision(pred_y,true_y,labels):
    """
    多类的精确率
    对于预测为正的样本中有多少是真正的正例
    :param pre_y: 预测结果
    :param true_y: 真实标签
    :param labels: 标签列表
    :return:
    """
    if isinstance(pred_y[0],list):
        pred_y=[item[0] for item in pred_y]
    precisions=[binary_precision(pred_y,true_y,label) for label in labels]
    #把每个类别作为正例,其他作为负例计算,放进列表中
    prec=mean(precisions)
    return prec
    
    def multi_recall(pred_y,true_y,labels):
    """
    多分类的召回率
    对数据中正例有多少被预测正确
    :param pre_y: 预测结果
    :param true_y: 真实结果
    :param labels: 标签列表
    :return:
    """
    if isinstance(pred_y[0],list):
        pred_y=[item[0] for item in pred_y]
    recalls=[binary_recall(pred_y,true_y,label) for label in labels]
    rec=mean(recalls)
    return rec
    
    def multi_f_beta(pred_y,true_y,labels,beta=1.0):
    """
    多分类的f值
    :param pred_y: 预测结果
    :param true_y: 真实结果
    :param labels: 标签列表
    :param beta: beta值
    :return:
    """
    if isinstance(pred_y[0],list):
        pred_y=[item[0] for item in pred_y]
    f_betas = [binary_f_beta(pred_y, true_y, beta, label) for label in labels]
    f_beta = mean(f_betas)
    return f_beta
    
    def get_binary_metrics(pred_y,true_y,f_beta=1.0):
    """
    得到二分类的性能指标
    :param pred_y:
    :param true_y:
    :param f_beta:
    :return:
    """
    acc = accuracy(pred_y, true_y)
    recall = binary_recall(pred_y, true_y)
    precision = binary_precision(pred_y, true_y)
    f_beta = binary_f_beta(pred_y, true_y, f_beta)
    return acc, recall, precision, f_beta
    
    def get_multi_metrics(pred_y,true_y,labels,f_beta=1.0):
    """
    多分类的性能指标
    :param pred_y:
    :param true_y:
    :param labels:
    :param f_beta:
    :return:
    """
    acc = accuracy(pred_y, true_y)
    recall = multi_recall(pred_y, true_y, labels)
    precision = multi_precision(pred_y, true_y, labels)
    f_beta = multi_f_beta(pred_y, true_y, labels, f_beta)
    return acc, recall, precision, f_beta
    
    
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-16/X7al6sDNERHpbzoMBdmAykhq4GFY.png)
训练模型
复制代码
       #训练模型
    #生成训练集和验证集
    trainSentences=data.trainSentences
    trainLabels=data.trainLabels
    evalSentences=data.evalSentences
    evalLabels=data.evalLabels
    
    wordEmbedding=data.wordEmbedding
    labelList=data.labelList
    
    
    #定义图计算
    with tf.Graph().as_default():
    #使用tf.ConfigProto()配置Session参数
    session_conf=tf.ConfigProto(allow_soft_placement=True,log_device_placement=False)
    #是配置tf.Session的运算方式,比如gpu运算或者cpu运算
    #log_device_placement=True  设置为True时,会打印出TensorFlow使用了那种操作
    session_conf.gpu_options.allow_growth=True #动态申请显存
    session_conf.gpu_options.per_process_gpu_memory_fraction=0.9 #限制GPU的使用率
    
    sess=tf.Session(config=session_conf)
    
    #定义会话
    with sess.as_default():
        cnn=TextCNN(config,wordEmbedding)
    
        #权重优化,也就是更新的步数
        globalStep=tf.Variable(0,name='gloabalStep',trainable=False)
        #定义优化器,传入学习速率参数
        optimizer=tf.train.AdamOptimizer(config.training.learningRate)
        #计算梯度,得到梯度和变量
        gradsAndVars=optimizer.compute_gradients(cnn.loss)
        #返回的是元组列表[(gradient,variable),…]
        #将梯度应用在变量下,生成训练器
        trainOp=optimizer.apply_gradients(gradsAndVars,global_step=globalStep)
    
        #用summary绘制tensorBoard
        gradSummaries=[]
        for g,v in gradsAndVars:
            if g is not None:
                tf.summary.histogram('{}/grad/his'.format(v.name),g) #用来显示直方图信息
                tf.summary.scalar('{}/grad/sparsity'.format(v.name),tf.nn.zero_fraction((g)))#用来显示标量信息
    
        outDir=os.path.abspath(os.path.join(os.path.curdir,'summarys'))
        #返回绝对路径
        print("Writing to {}\n".format(outDir))
    
        lossSummary=tf.summary.scalar('loss',cnn.loss)
        summaryOp=tf.summary.merge_all()
    
        trainSummaryDir = os.path.join(outDir, "train")
        trainSummaryWriter = tf.summary.FileWriter(trainSummaryDir, sess.graph)
    
        evalSummaryDir = os.path.join(outDir, "eval")
        evalSummaryWriter = tf.summary.FileWriter(evalSummaryDir, sess.graph)
    
        #初始化所有变量
    
        #保存模型的对象saver
        saver=tf.train.Saver(tf.global_variables(),max_to_keep=5) #max_to_keep=5,保存最近的5个模型
    
        #保存模型的一种方式,保存为pb文件
        savedModelPath='./model/textCNN/savedModel'
        if os.path.exists(savedModelPath):
            os.rmdir(savedModelPath)
        builder=tf.saved_model.builder.SavedModelBuilder(savedModelPath)
    
        sess.run(tf.global_variables_initializer())
        #global_variables_initializer 返回一个用来初始化 计算图中所有global variable的 op
    
        def trainStep(batchX,batchY):
            """
            训练函数  定义1batch
            """
            feed_dict={
                cnn.inputX:batchX,
                cnn.inputY:batchY,
                cnn.dropoutKeepProb:config.model.dropoutKeepProb
            }
            _,summary,step,loss,predictions=sess.run(
                [trainOp,summaryOp,globalStep,cnn.loss,cnn.predictions],
                feed_dict
            )
            """
            sess每执行完一个batch,就给global_step加1,用来统计目前执行的batch数
            """
            timeStr=datetime.datetime.now().isoformat()
    
            acc,recall,prec,f_beta=get_multi_metrics(pred_y=predictions,true_y=batchY,labels=labelList)
    
            trainSummaryWriter.add_summary(summary,step)
    
            return loss,acc,prec,recall,f_beta
    
        def devStep(batchX,batchY):
            """
            验证函数
            """
            feed_dict={
                cnn.inputX:batchX,
                cnn.inputY:batchY,
                cnn.dropoutKeepProb:1.0
            }
            summary,step,loss,predictions=sess.run(
                [summaryOp,globalStep,cnn.loss,cnn.predictions],
                feed_dict
            )
    
            acc,precision,recall,f_beta=get_multi_metrics(pred_y=predictions,true_y=batchY,labels=labelList)
    
            evalSummaryWriter.add_summary(summary,step)
    
            return loss,acc,precision,recall,f_beta
    
        for i in range(config.training.epoches):#轮数
            #训练模型
            print('start training model')
            for batchTrain in nextBatch(trainSentences,trainLabels,config.batchSize): #总批次
                loss,acc,prec,recall,f_beta=trainStep(batchTrain[0],batchTrain[1])
                currentStep=tf.train.global_step(sess,globalStep)
                #global_step记录的其实是train阶段每一步的索引
                #currentStep记录执行的第几个batch
                print('train:step:{},loss:{},acc:{},recall:{},precision:{},f_beta:{}'.format
                      (currentStep,loss,acc,recall,prec,f_beta))
                if currentStep%config.training.evaluateEvery==0: #每100步训练输出一次1轮的评估
                    print('\nEvalution:')
                    losses=[]
                    accs=[]
                    f_betas=[]
                    precisions=[]
                    recalls=[]
    
                    for batchEval in nextBatch(evalSentences,evalLabels,config.batchSize):
                        loss,acc,precision,recall,f_beta=devStep(batchEval[0],batchEval[1])
                        losses.append(loss)
                        accs.append(acc)
                        f_betas.append(f_beta)
                        precisions.append(precision)
                        recalls.append(recall)
    
                    time_str=datetime.datetime.now().isoformat()
                    print('{},step:{},loss:{},acc:{},precision:{},recall:{},f_beta:{}'.format(
                        time_str,currentStep,mean(losses),mean(accs),mean(precisions),mean(recalls),mean(f_betas)
                    ))
    
                    if currentStep%config.training.checkpointEvery==0:
                        #每100步保存模型
                        #保存模型的另一种方法,保存checkpoint文件
                        path=saver.save(sess,'./model/textCNN/model/my-model',global_step=currentStep)
                        print('Saved model checkpoint to {}\n'.format(path))
    
        inputs={'inputX':tf.saved_model.utils.build_tensor_info(cnn.inputX),
                'keepProb':tf.saved_model.utils.build_tensor_info(cnn.dropoutKeepPro)}
        #tf.saved_model.utils.build_tensor_info是把变量变成可缓存对象的函数
        outputs = {"predictions": tf.saved_model.utils.build_tensor_info(cnn.predictions)}
    
        prediction_signature=tf.saved_model.signature_def_utils.build_signature_def(inputs=inputs,outputs=outputs,
                                                                                    method_name=tf.saved_model.signature_constants.PREDICT_METHOD_NAME)
        #SignatureDef的主要作用是定义输出和输入接口协议
        legacy_init_op = tf.group(tf.tables_initializer(), name="legacy_init_op")
        builder.add_meta_graph_and_variables(sess, [tf.saved_model.tag_constants.SERVING],
                                             signature_def_map={"predict": prediction_signature},
                                             legacy_init_op=legacy_init_op)
    
        builder.save()
        """
        先构建builder对象;再用builder.add_meta_graph_and_variables(...)方法将与训练模型的图和参数值添加到builder中;
        最后调用builder.save()将pretrain model保存成saved model。
        """
    
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-16/YF2ZOnouAxfyTMesDlzpLRmHcB5Q.png)

权重更新:tensorflow——optimizer.minimize()、optimizer.compute_gradients()、optimizer.apply_gradients()
将学习速率传给优化器
通过损失计算梯度和变量
将梯度给优化器,优化器来优化参数
模型的恢复与保存:tensorflow 1.0 学习:模型的保存与恢复(Saver)
模型的保存Tensorflow serving 学习(一)
开始训练模型
在这里插入图片描述
在这里插入图片描述
分享一个tensorboard的界面介绍tensorflow学习笔记----TensorBoard讲解
可以打开随时观察loss变化
在这里插入图片描述

全部评论 (0)

还没有任何评论哟~