tensorflow1.x第三篇

完整的全连接网络识别手写数字
baseline:在手写数字识别中加入:正则化,学习率衰减策略,参数的滑动平均,测试。

#forward
import tensorflow as tf

INPUT_NODE = 784
LAYER1_NODE = 500
OUTPUT_NODE = 10

def get_weight(shape,regularizer):
    w = tf.Variable(tf.truncated_normal(shape,stddev=0.1))
    '''
    加入正则化项
    '''
    if regularizer!=None:
        tf.add_to_collection('losses',tf.contrib.layers.l2_regularizer(regularizer)(w))
    return w
def get_bias(shape):
    b = tf.Variable(tf.zeros(shape))
    return b

def forward(x,regularizer):
    w1 = get_weight([INPUT_NODE,LAYER1_NODE],regularizer)
    b1 = get_bias([LAYER1_NODE])
    y1 = tf.nn.relu(tf.matmul(x,w1)+b1)

    w2 = get_weight([LAYER1_NODE,OUTPUT_NODE],regularizer)
    b2 = get_bias([OUTPUT_NODE])
    y = tf.matmul(y1,w2)+b2
    return y
#backward
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
import forward
import os

BATCH_SIZE = 200
LEARNING_RATE_BASE = 0.1
LEARNING_RATE_DECAY = 0.99
REGULARIZER = 0.0001
STEPS = 50000
MOVING_AVERAGE_DECAY = 0.99
MODEL_SAVE_PATH = "./model/"
MODEL_NAME = "mnist_model"

def backward(mnist):
    x = tf.placeholder(tf.float32,[None,forward.INPUT_NODE])
    y_ = tf.placeholder(tf.float32,[None,forward.OUTPUT_NODE])
    y = forward.forward(x,REGULARIZER)
    global_step = tf.Variable(0,trainable=False)

    ce = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y,labels=tf.argmax(y_,1))
    cem = tf.reduce_mean(ce)
    #tf.get_collection(“”)函数表示从 collection 集合中取出全部变量生成一个列表。
    #tf.add( )函数表示将参数列表中对应元素相加。
    loss = cem + tf.add_n(tf.get_collection('losses'))

    learning_rate = tf.train.exponential_decay(
        LEARNING_RATE_BASE,
        global_step,
        mnist.train.num_examples / BATCH_SIZE,
        LEARNING_RATE_DECAY,
        staircase=True
        )
    train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss,global_step)

    ema = tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY,global_step)
    ema_op = ema.apply(tf.trainable_variables())
    with tf.control_dependencies([train_step,ema_op]):
        train_op = tf.no_op(name='train')

    saver = tf.train.Saver()

    with tf.Session() as sess:
        sess.run(tf.global_variables_initializer())
        for i in range(STEPS):
            #把数据以批次大小付给xs,ys
            xs,ys = mnist.train.next_batch(BATCH_SIZE)
            _,loss_dis,step = sess.run([train_op,loss,global_step],feed_dict={x:xs,y_:ys})
            if i %1000==0:
                print("After %d training step(s), loss on training batch is %g." % (step, loss_dis))
                '''
                在反向传播过程中,一般会间隔一定轮数保存一次神经网络模型,并产生三个
                文件(保存当前图结构的.meta 文件、保存当前参数名的.index 文件、保存当
                前参数的.data 文件)
                '''
                saver.save(sess,os.path.join(MODEL_SAVE_PATH,MODEL_NAME),global_step)
if __name__ == '__main__':
    '''
    使用 input_data 模块中的 read_data_sets()函数加载 mnist 数据集:
    read_data_sets()函数中有两个参数,第一个参数表示数据集存放路径,第
二个参数表示数据集的存取形式。当第二个参数为 Ture 时,表示以独热码形式
存取数据集。read_data_sets()函数运行时,会检查指定路径内是否已经有数据
集,若指定路径中没有数据集,则自动下载,并将 mnist 数据集分为训练集 train、
验证集 validation 和测试集 test 存放
    '''
    mnist = input_data.read_data_sets("./data/", one_hot=True)
    backward(mnist)
out:
After 44001 training step(s), loss on training batch is 0.125637.
After 45001 training step(s), loss on training batch is 0.126251.
After 46001 training step(s), loss on training batch is 0.127588.
After 47001 training step(s), loss on training batch is 0.121614.
After 48001 training step(s), loss on training batch is 0.125201.
After 49001 training step(s), loss on training batch is 0.128203.

Process finished with exit code 0


#test
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
import forward
import backward

def test(mnist):
    '''
    tf.Graph( ).as_default( )函数表示将当前图设置成为默认图,并返回一
    个上下文管理器。该函数一般与 with 关键字搭配使用,应用于将已经定义好
    的神经网络在计算图中复现。
    '''
    with tf.Graph().as_default() as g:
        x = tf.placeholder(tf.float32,[None,forward.INPUT_NODE])
        y_ = tf.placeholder(tf.float32,[None,forward.OUTPUT_NODE])
        y = forward.forward(x,None)

        '''
        加载模型中参数的滑动平均值
        在保存模型时,若模型中采用滑动平均,则参数的滑动平均值会保存在相应文件
        中。通过实例化 saver 对象,实现参数滑动平均值的加载
        ema = tf.train.ExponentialMovingAverage(滑动平均基数)
        ema_restore = ema.variables_to_restore() 
        saver = tf.train.Saver(ema_restore)
        '''
        ema = tf.train.ExponentialMovingAverage(backward.MOVING_AVERAGE_DECAY)
        ema_restore = ema.variables_to_restore()
        saver = tf.train.Saver(ema_restore)

        #tf.equal( )函数表示对比两个矩阵或者向量的元素。若对应元素相等,则返回 True;若对应元素不相等,则返回 False。
        correct_prediction = tf.equal(tf.argmax(y_,1),tf.argmax(y,1))
        #tf.cast(x,dtype)函数表示将参数 x 转换为指定数据类型。
        accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32))

        with tf.Session() as sess:
            '''
            with tf.Session() as sess: 
                ckpt = tf.train.get_checkpoint_state(存储路径) 
                if ckpt and ckpt.model_checkpoint_path: 
                    saver.restore(sess, ckpt.model_checkpoint_path)
            '''
            ckpt = tf.train.get_checkpoint_state(backward.MODEL_SAVE_PATH)
            if ckpt and ckpt.model_checkpoint_path:
                saver.restore(sess,ckpt.model_checkpoint_path)
                global_step = ckpt.model_checkpoint_path.split('/')[-1].split('-')[-1]
                accuracy_score = sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels})
                print("After %s training step(s), test accuracy = %g" % (global_step, accuracy_score))
            else:
                print('No checkpoint file found')
                return
if __name__ == '__main__':
    mnist = input_data.read_data_sets("./data/", one_hot=True)
    test(mnist)
out:
After 49001 training step(s), test accuracy = 0.9799

Process finished with exit code 0

加入断点续训,形成应用,制作tfrecord数据集。

#generateds
import tensorflow as tf
import numpy as np
import os
from PIL import Image

image_train_path = 'mnist_data_jpg/mnist_train_jpg_60000/'
label_train_path = 'mnist_data_jpg/mnist_train_jpg_60000.txt'
tfRecord_train='./data/mnist_train.tfrecords'
image_test_path = 'mnist_data_jpg/mnist_test_jpg_10000/'
label_test_path = 'mnist_data_jpg/mnist_test_jpg_10000.txt'
tfRecord_test='./data/mnist_test.tfrecords'
data_path = './data'
resize_height = 28
resize_weight = 28
'''
tfrecords 文件 
1)tfrecords:是一种二进制文件,可先将图片和标签制作成该格式的文件。
使用 tfrecords 进行数据读取,会提高内存利用率。
2)tf.train.Example: 用来存储训练数据。训练数据的特征用键值对的形式表
示。 如:‘ img_raw ’ :值 ‘ label ’ :值 值是 Byteslist/FloatList/Int64List
3)SerializeToString( ):把数据序列化成字符串存储。
'''
def write_tfRecord(tfRecordName,image_path,label_path):
    writer = tf.python_io.TFRecordWriter(tfRecordName)
    num_pic = 0
    f = open(label_path,'r')
    contents = f.readlines()
    f.close()
    for content in contents:
        value = content.split()
        img_path = image_path+value[0]
        img = Image.open(img_path)
        img_raw = img.tobytes()
        labels = [0]*10
        labels[int(value[1])] = 1

        # 把每张图片和标签封装到 example 中
        example = tf.train.Example(features=tf.train.Features(feature={
            'img_raw':tf.train.Feature(bytes_list=tf.train.BytesList(value=[img_raw])),
            'label': tf.train.Feature(int64_list=tf.train.Int64List(value=labels))
        }))
        # 把 example 进行序列化
        writer.write(example.SerializeToString())
        num_pic +=1
        print("the number of picture:", num_pic)
    writer.close()
    print("write tfrecord successful")
def generate_tfRecord():
    isExists = os.path.exists(data_path)
    if not isExists:
        os.makedirs(data_path)
        print('The directory was created successfully')
    else:
        print('directory already exists')
    write_tfRecord(tfRecord_train,image_train_path,label_train_path)
    write_tfRecord(tfRecord_test,image_test_path,label_test_path)


def read_tfRecord(tfRecord_path):
    '''
    filename_queue = tf.train.string_input_producer([tfRecord_path])
    tf.train.string_input_producer( string_tensor,
                                    num_epochs=None,
                                    shuffle=True,
                                    seed=None,
                                    capacity=32,
                                    shared_name=None,
                                    name=None,
                                    cancel_op=None)
    该函数会生成一个先入先出的队列,文件阅读器会使用它来读取数据。
    参数说明:string_tensor: 存储图像和标签信息的 TFRecord 文件名列表
            num_epochs: 循环读取的轮数(可选)
            shuffle:布尔值(可选),如果为 True,则在每轮随机打乱读取顺序
            seed:随机读取时设置的种子(可选)
            capacity:设置队列容量
            shared_name:(可选)  如果设置,该队列将在多个会话中以给定名
                                 称共享。所有具有此队列的设备都可以通过 shared_name 访问它。在分布式设置
                                 中使用这种方法意味着每个名称只能被访问此操作的其中一个会话看到。
            name:操作的名称(可选)
            cancel_op:取消队列(None)
    '''
    filename_queue = tf.train.string_input_producer([tfRecord_path], shuffle=True)
    reader = tf.TFRecordReader()
    _, serialized_example = reader.read(filename_queue)
    '''
    把读出的每个样本保存在 serialized_example 中进行解序列化,标签和图片的
    键名应该和制作 tfrecords 的键名相同,其中标签给出几分类。
    
    该函数可以将 tf.train.Example 协议内存块(protocol buffer)解析为张量。
    参数说明:
    serialized: 一个标量字符串张量
    features: 一个字典映射功能键 FixedLenFeature 或 VarLenFeature
              值,也就是在协议内存块中储存的
    name:操作的名称(可选)
    example_names: 标量字符串联的名称(可选)
    
    '''
    features = tf.parse_single_example(serialized_example,
                                       features={
                                           'label': tf.FixedLenFeature([10], tf.int64),
                                           'img_raw': tf.FixedLenFeature([], tf.string)
                                       })
    #将 img_raw 字符串转换为 8 位无符号整型
    img = tf.decode_raw(features['img_raw'], tf.uint8)
    #将形状变为一行 784 列
    img.set_shape([784])
    img = tf.cast(img, tf.float32) * (1. / 255)
    label = tf.cast(features['label'], tf.float32)
    return img, label
def get_tfRecord(num,isTrain=True):
    if isTrain:
        tfRecord_path = tfRecord_train
    else:
        tfRecord_path = tfRecord_test
    img,label = read_tfRecord(tfRecord_path)
    '''
    tf.train.shuffle_batch( tensors,
                            batch_size,
                            capacity,
                            min_after_dequeue,
                            num_threads=1,
                            seed=None,
                            enqueue_many=False,
                            shapes=None,
                            allow_smaller_final_batch=False,
                            shared_name=None,
                            name=None)
    这个函数随机读取一个 batch 的数据。
    参数说明:
            tensors: 待乱序处理的列表中的样本(图像和标签)
            batch_size: 从队列中提取的新批量大小
            capacity:队列中元素的最大数量
            min_after_dequeue: 出队后队列中的最小数量元素,用于确保元素的混合级别
            num_threads: 排列 tensors 的线程数
            seed:用于队列内的随机洗牌
            enqueue_many: tensor 中的每个张量是否是一个例子
            shapes: 每个示例的形状
            allow_smaller_final_batch: (可选)布尔值。 如果为 True,则在队列中剩余数量不足时允许最终批次更小。
            shared_name:(可选)如果设置,该队列将在多个会话中以给定名称共享。
            name:操作的名称(可选)
    '''
    img_batch,label_batch = tf.train.shuffle_batch([img,label],
                                                   batch_size=num,
                                                   num_threads=2,
                                                   capacity=1000,
                                                   min_after_dequeue=700)
    return img_batch, label_batch
if __name__ == '__main__':
    generate_tfRecord()
#forward
import tensorflow as tf

INPUT_NODE = 784
OUTPUT_NODE = 10
LAYER1_NODE = 500


def get_weight(shape, regularizer):
    w = tf.Variable(tf.truncated_normal(shape, stddev=0.1))
    if regularizer != None: tf.add_to_collection('losses', tf.contrib.layers.l2_regularizer(regularizer)(w))
    return w


def get_bias(shape):
    b = tf.Variable(tf.zeros(shape))
    return b


def forward(x, regularizer):
    w1 = get_weight([INPUT_NODE, LAYER1_NODE], regularizer)
    b1 = get_bias([LAYER1_NODE])
    y1 = tf.nn.relu(tf.matmul(x, w1) + b1)

    w2 = get_weight([LAYER1_NODE, OUTPUT_NODE], regularizer)
    b2 = get_bias([OUTPUT_NODE])
    y = tf.matmul(y1, w2) + b2
    return y
#backward
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
import forward
import os
import generateds  # 1

BATCH_SIZE = 200
LEARNING_RATE_BASE = 0.1
LEARNING_RATE_DECAY = 0.99
REGULARIZER = 0.0001
STEPS = 50000
MOVING_AVERAGE_DECAY = 0.99
MODEL_SAVE_PATH = "./model/"
MODEL_NAME = "mnist_model"
train_num_examples = 60000  # 2


def backward():
    x = tf.placeholder(tf.float32, [None, forward.INPUT_NODE])
    y_ = tf.placeholder(tf.float32, [None, forward.OUTPUT_NODE])
    y = forward.forward(x, REGULARIZER)
    global_step = tf.Variable(0, trainable=False)

    ce = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y, labels=tf.argmax(y_, 1))
    cem = tf.reduce_mean(ce)
    loss = cem + tf.add_n(tf.get_collection('losses'))

    learning_rate = tf.train.exponential_decay(
        LEARNING_RATE_BASE,
        global_step,
        train_num_examples / BATCH_SIZE,
        LEARNING_RATE_DECAY,
        staircase=True)

    train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss, global_step=global_step)

    ema = tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY, global_step)
    ema_op = ema.apply(tf.trainable_variables())
    with tf.control_dependencies([train_step, ema_op]):
        train_op = tf.no_op(name='train')

    saver = tf.train.Saver()
    img_batch, label_batch = generateds.get_tfRecord(BATCH_SIZE, isTrain=True)  # 3

    with tf.Session() as sess:
        init_op = tf.global_variables_initializer()
        sess.run(init_op)

        '''
        加入断点续训:
        tf.train.get_checkpoint_state(checkpoint_dir,latest_filename=None)
        该函数表示如果断点文件夹中包含有效断点状态文件,则返回该文件。
        参数说明:checkpoint_dir:表示存储断点文件的目录
        latest_filename=None:断点文件的可选名称,默认为“checkpoint” 
        
        saver.restore(sess, ckpt.model_checkpoint_path)
        该函数表示恢复当前会话,将 ckpt 中的值赋给 w 和 b。
        参数说明:sess:表示当前会话,之前保存的结果将被加载入这个会话
        ckpt.model_checkpoint_path:表示模型存储的位置,不需要提供模
        型的名字,它会去查看 checkpoint 文件,看看最新的是谁,叫做什么。
        '''
        ckpt = tf.train.get_checkpoint_state(MODEL_SAVE_PATH)
        if ckpt and ckpt.model_checkpoint_path:
            saver.restore(sess, ckpt.model_checkpoint_path)


        '''
        利用多线程提高图片和标签的批获取效率 方法:将批获取的操作放到线程协调器开启和关闭之间
        '''
        coord = tf.train.Coordinator()  # 4
        '''
        tf.train.start_queue_runners( sess=None,
                                      coord=None,
                                      daemon=True,
                                      start=True,
                                      collection=tf.GraphKeys.QUEUE_RUNNERS)
        这个函数将会启动输入队列的线程,填充训练样本到队列中,以便出队操作可以
        从队列中拿到样本。这种情况下最好配合使用一个 tf.train.Coordinator ,这
        样可以在发生错误的情况下正确地关闭这些线程。
        参数说明:
                sess:用于运行队列操作的会话。 默认为默认会话。
                coord:可选协调器,用于协调启动的线程。
                daemon: 守护进程,线程是否应该标记为守护进程,这意味着它们不会阻止程序退出。
                start:设置为 False 只创建线程,不启动它们。
                collection:指定图集合以获取启动队列的 GraphKey。默认为GraphKeys.QUEUE_RUNNERS
        '''
        threads = tf.train.start_queue_runners(sess=sess, coord=coord)  # 5

        for i in range(STEPS):
            xs, ys = sess.run([img_batch, label_batch])  # 6
            _, loss_value, step = sess.run([train_op, loss, global_step], feed_dict={x: xs, y_: ys})
            if i % 1000 == 0:
                print("After %d training step(s), loss on training batch is %g." % (step, loss_value))
                saver.save(sess, os.path.join(MODEL_SAVE_PATH, MODEL_NAME), global_step=global_step)

        coord.request_stop()  # 7
        coord.join(threads)  # 8
def main():
    backward()  # 9
if __name__ == '__main__':
    main()
#test
import time
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
import forward
import backward
import generateds

TEST_INTERVAL_SECS = 5
TEST_NUM = 10000  # 1


def test():
    with tf.Graph().as_default() as g:
        x = tf.placeholder(tf.float32, [None, forward.INPUT_NODE])
        y_ = tf.placeholder(tf.float32, [None, forward.OUTPUT_NODE])
        y = forward.forward(x, None)

        ema = tf.train.ExponentialMovingAverage(backward.MOVING_AVERAGE_DECAY)
        ema_restore = ema.variables_to_restore()
        saver = tf.train.Saver(ema_restore)

        correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
        accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

        img_batch, label_batch = generateds.get_tfRecord(TEST_NUM, isTrain=False)  # 2

        with tf.Session() as sess:
            ckpt = tf.train.get_checkpoint_state(backward.MODEL_SAVE_PATH)
            if ckpt and ckpt.model_checkpoint_path:
                saver.restore(sess, ckpt.model_checkpoint_path)
                global_step = ckpt.model_checkpoint_path.split('/')[-1].split('-')[-1]

                coord = tf.train.Coordinator()  # 3
                threads = tf.train.start_queue_runners(sess=sess, coord=coord)  # 4

                xs, ys = sess.run([img_batch, label_batch])  # 5

                accuracy_score = sess.run(accuracy, feed_dict={x: xs, y_: ys})

                print("After %s training step(s), test accuracy = %g" % (global_step, accuracy_score))

                coord.request_stop()  # 6
                coord.join(threads)  # 7

            else:
                print('No checkpoint file found')
                return


if __name__ == '__main__':
    test()
import tensorflow as tf
import numpy as np
from PIL import Image
import backward
import forward
import os

def restore_model(testPicArr):
    with tf.Graph().as_default() as tg:
        x = tf.placeholder(tf.float32, [None, forward.INPUT_NODE])
        y = forward.forward(x, None)
        preValue = tf.argmax(y, 1)

        variable_averages = tf.train.ExponentialMovingAverage(backward.MOVING_AVERAGE_DECAY)
        variables_to_restore = variable_averages.variables_to_restore()
        saver = tf.train.Saver(variables_to_restore)

        with tf.Session() as sess:
            ckpt = tf.train.get_checkpoint_state(backward.MODEL_SAVE_PATH)
            if ckpt and ckpt.model_checkpoint_path:
                saver.restore(sess, ckpt.model_checkpoint_path)

                preValue = sess.run(preValue, feed_dict={x: testPicArr})
                return preValue
            else:
                print("No checkpoint file found")
                return -1


def pre_pic(picName):
    img = Image.open(picName)
    reIm = img.resize((28, 28), Image.ANTIALIAS)
    im_arr = np.array(reIm.convert('L'))
    threshold = 50
    for i in range(28):
        for j in range(28):
            #模型的要求是黑底白字,但输入的图是白底黑字,所以需要对每个像素点的值改为 255 减去原值以得到互补的反色。
            im_arr[i][j] = 255 - im_arr[i][j]
            # 对图片做二值化处理(这样以滤掉噪声,另外调试中可适当调节阈值)。
            if (im_arr[i][j] < threshold):
                im_arr[i][j] = 0
            else:
                im_arr[i][j] = 255

    nm_arr = im_arr.reshape([1, 784])
    nm_arr = nm_arr.astype(np.float32)
    #把图片形状拉成 1 行 784 列,并把值变为浮点型(因为要求像素点是 0-1之间的浮点数)。
    img = np.multiply(nm_arr, 1.0 / 255.0)

    return nm_arr  # img

def application():
    for i in range(10):
        testpic_path = os.path.join('./pic',str(i)+'.png')
        testPicArr = pre_pic(testpic_path)
        preValue = restore_model(testPicArr)
        print("The prediction number is:", preValue)
if __name__ == '__main__':
    application()
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值