人工智能深度学习笔记

文章目录

一、深度学习

1.1、深度学习介绍

1.1.1、深度学习与机器学习的区别
1.1.1.1、特征提取方面
  • 机器学习的特征工程步骤是要靠手动完成的,而且需要大量领域专业知识
  • 深度学习通常有多个层组成,它们通常将简单的模型组合在一起,将数据从一层传递到另一层来构建更复杂的模型。通过训练大量数据自动得出模型,不需要人工特征提取环节
1.1.1.2、数据量和计算性能要求
  • 机器学习需要的执行时间远少于深度学习,深度学习参数往往很庞大,需要通过大量数据的多次优化来训练参数。
    • 深度学习需要大量的训练数据集
    • 训练深度神经网络需要大量的算力
      • 需要强大的GPU服务器来进行计算
      • 全面管理的分布式训练与预测服务----比如谷歌、TensorFlow、 云机器学习平台
1.1.1.3、算法代表
  • 机器学习
    • 朴素贝叶斯、决策树等
  • 深度学习
    • 神经网络
1.1.2、深度学习的应用场景
  • 图像识别
    • 物体识别
    • 场景识别
    • 车型识别
    • 人脸检测跟踪
    • 人脸关键点定位
    • 人脸身份技术
  • 自然语言处理技术
    • 机器翻译
    • 文本识别
    • 聊天对话
  • 语音技术
    • 语音识别
1.1.3、深度学习框架
框架名主语言从语言灵活性上手难度开发者
TensoflowC++cuda/pythonGoogle
CaffeC++cuda/python/Matlab一般中等贾杨清
PyTorchpythonC/C++中等FaceBook
MXNetC++cuda/R/julia中等李沐和陈天奇等
TorchluaC/cuda中等Facebook
TheanopythonC++/cuda蒙特利尔理工学院

二、TensorFlow框架

2.1、TensorFlow简介

2.1.1、TensorFlow的特点
  • 高度灵活
  • 语言多样
  • 设备支持
  • Tencorboard可视化
    • TensorBoard是TensorFlow的一组Web应用,用来监视Tencorflow运行过程
2.2.2、TensorFlow安装
  • CPU版本
    • pip install tensorflow -i https://mirrors.aliyun.com/pypi/simple
  • GPU版本
    • GPU
      • 核芯数量更多,适用于并行任务

2.2、TensorFlow的结构

2.2.1、案例:TF实现加法运算
2.2.2、TensorFlow结构分析
  • TensorFlow程序通常被组织成一个构建图阶段和一个执行图阶段
    • 在构建阶段,数据与操作的执行步骤被描述成一个图
    • 在执行阶段,使用会话执行构建好的图中的操作
      • 图和会话
        • 图:这是TensorFlow将计算表示为指令之间的依赖关系的一种表示法
        • 会话(2.0已经废弃):TensorFlow跨一个或多个本地或远程设备运行数据流图的机制
      • 张量(Tensor)
        • TensorFlow中的基本数据对象
      • 节点(Op)
        • 提供图当中执行的操作
  • 数据流图
    • TensorFlow是一个采用数据流图(data flow graphs), 用于数据计算的开源框架。
    • 节点(Operation)在图中表示数学操作,线(edges)则表示在节点间相互联系的多维数据数组,即张量(tensor)

2.3、TensorFlow的各个组件

2.3.1、图与TensorBoard
2.3.1.1、什么是图结构
  • 图包含了一组tf.Operation代表的计算单元对象和tf.Tensor代表的计算单元之间流动的数据
2.3.1.2、图相关操作
  • 默认图
    • 查看默认图
      • 调用方法
        • tf.get_deflaut_graph()
      • 查看属性
        • .graph()
  • 创建图
    • new_g = tf.Graph()
2.3.1.3、TensorBoard可视化
  • 数据序列化-events文件
  • 启动tensorBoard
2.3.1.4、OP
  • 操作函数
    • tf.constant()
    • tf.add()
  • 操作对象
    • tf.const
  • 指令名称
    • name=
2.3.1.5、会话(2.0以上已废弃)
  • 交互式环境
  • 占位符
2.3.1.6、张量
  • 张量(Tensor)

    • 张量就是一个n维数组,类型为tf.Tensor
      • type:数据类型
      • shape:形状(阶)
    • 创建张量的时候,如果不指定类型默认
      • 整型 tf.int32
      • 浮点 tf.float32
  • 创建张量的指令

    • # 固定值0张量
      a = tf.zeros(shape=[3, 4])
      # 固定值1张量
      a = tf.ones(shape=[3, 4])
      # 固定值value张量
      a = tf.constant(2, shape=[3, 4])
      # 随机值张量
      # TODO
      
  • 张量的变换

    • 类型转换

      tensor_new = tf.cast(tensor1, dtype=tf.int32)
      
    • 形状改变

      • 静态形状

        • 初始创建张量时的形状
        • 如何改变静态形状
          • 只有在形状没有完全固定下来时才能改变静态形状(placeholder占位符定义的)
          • tensor.set_shape()
      • 动态形状

        • 如何改变动态形状

          • tf.reshape(tensor,shape)
          • 元素数量必须匹配
          tensor2 = tf.constant([1, 2, 3, 4])
          a = tf.reshape(tensor2, [2, 2])
          print(a)
          
  • 张量的数学运算

    • 算数运算
    • 基本数学函数
    • 矩阵运算
    • reduce运算
    • 序列索引操作
2.3.1.7、变量
  • 变量

    • 存储持久化
    • 可修改值
    • 可指定被训练
  • 创建变量

    • tf.Variable(initial_value=None, trainable=True, constraint=None, name=None)

      • initial_value 初始化的值
      • trainable 是否被训练
      • constraint
      a = tf.Variable(initial_value=50)
          b = tf.Variable(initial_value=60)
          c = tf.add(a, b)
          print(a)
          print(b)
          print(c)
      
  • 变量命名空间的修改

2.3.1.8、API
  • 基础API
    • tf.app
      • main函数入口
    • tf.image
      • 图像处理操作
    • tf.gfile
      • 文件操作函数
    • tf.summary
      • 生成TensorBoard可用的统计日志
    • tf.python_io
      • 用来读写TFRecords文件
    • tf.train
      • 提供训练器,与tf.nn组合实现网络的优化计算
    • tf.nn
      • 这个模块提供了一些构建神经网络的底层函数,TensorFlow构建网络的核心模块。其中包含了添加各种层的函数,比如添加卷积层,池化层等
  • 高级API
    • tf.keras
      • 快速构建模型
    • tf.layers
      • 以更高级的概念层来定义一个模型
    • tf.contrib
      • tf.contrib.layers提供将计算图中的网络层、正则化、摘要操作、是构建图的高级操作
    • tf.estimator
      • 相当于Model + Training + Evaluate的合体。在模块中,已经实现了几种简单的分类器和回归器

2.4、简单的线性回归案例

2.4.1、线性回归案例实现
def linear_regression():
    """
    自实现一个线性回归
    :return:
    """
    write = tf.summary.create_file_writer("./tmp/summary")
    with tf.name_scope("prepare_data") as scope:
        # 1.准备数据
        x = tf.random.normal(shape=[100, 1])
        y_true = tf.matmul(x, [[0.8]]) + 0.7

    with tf.name_scope("create_model"):
        # 2.构造模型
        # 定义模型参数,用变量
        weights = tf.Variable(initial_value=tf.random.normal(shape=[1, 1]))
        bias = tf.Variable(initial_value=tf.random.normal(shape=[1, 1]))

    # 4.优化损失
    print("训练前模型参数:权重%f,偏置%f" % (weights, bias))
    for i in range(200):
        if i == 0:
            tf.summary.trace_on(graph=True, profiler=True)
        loss = loader_demo(bias, weights, x, y_true)
        print("第%d次训练后模型参数:权重%f,偏置%f" % (i + 1, weights, bias))
        with write.as_default():
            tf.summary.scalar('loss', loss, step=i)

    with write.as_default():
        tf.summary.trace_export(
            name="my_func_trace5",
            step=0,
            profiler_outdir="./tmp/summary")


@tf.function
def loader_demo(bias, weights, x, y_true):
    with tf.GradientTape() as tape:  # 追踪梯度
        tape.watch([weights, bias])
        # 预测值
        y_predict = tf.matmul(x, weights) + bias
        # 3.构造损失函数
        loss = tf.reduce_mean(tf.square(y_predict - y_true))
    w, b = tape.gradient(loss, [weights, bias])  # 计算梯度
    # 梯度下降
    weights.assign_sub(0.01 * w)
    bias.assign_sub(0.01 * b)
    return loss
2.4.2、增加变量显示
  • 创建事件文件
  • 收集变量
  • 合并变量
  • 每次迭代运行一次合并变量
  • 每次迭代通过summary对象写入事件文件
    write = tf.summary.create_file_writer("./tmp/summary")   
    	with write.as_default():
            tf.summary.scalar('loss', loss, step=i)
2.4.3、添加命名空间
2.4.4、模型保存与加载
2.4.5、命令行参数设置
tf.compat.v1.app.flags.DEFINE_integer("max_step", 100, "训练模型步数")
FLAGS = tf.compat.v1.app.flags.FLAGS


def command_demo():
    """
    命令行参数演示
    :return:
    """
    print(FLAGS.max_step)
 python .\tensorflow_test.py --max_step=200

二、数据读取和神经网络基础

2.1、数据IO操作

2.1.1、文件读取流程
  • 多线程 + 队列

    1. 构造文件名队列
    2. 读取与解码
    3. 批处理

2.1.2、图片数据

2.1.2.1、图像基本知识
  • 如何将图片文件转换成机器学习算法可以处理的数据
    • 组成图片的最基本单位是像素
  • 图片三要素
    • 图片长度
    • 图片宽度
    • 图片通道数
  • 灰度图[长, 宽,1]
    • 每一个像素点[0, 255]的数
  • 彩色图[长,宽,3]
    • 每一个像素点3个[0, 255]的数
  • 张量形状
    • 一张图片shape = (height, width, channels)
    • 多张图片shape = (batch, height, width,channels)
2.1.2.2、图片特征值处理
  • 缩放图片到统一大小
2.1.2.3、数据格式
  • 存储:uint8(节约空间)
  • 矩阵计算:float32(提高精度)
2.1.2.4、案例:图片文件读取
def load_image(file_path, size=(32, 32)):
    # 读取与解码
    img = tf.io.read_file(file_path)
    img = tf.image.decode_jpeg(img)
    # 形状修改
    img = tf.image.resize(img, size) / 255.0
    return img


def picture_read():
    """
    狗图片读取
    :return:
    """
    # 构造文件名队列
    file_queue = tf.data.Dataset.list_files("./dog/*.jpg") \
        .map(load_image) \
        .batch(10)
    for i in file_queue:
        print(i)
2.1.2.5、案例:二进制文件读取
import tensorflow as tf


class Cifar(object):
    def __init__(self):
        # 初始化操作
        self.height = 32
        self.width = 32
        self.channels = 3

        # 字节数
        self.image_bytes = self.height * self.width * self.channels
        self.label_bytes = 1
        self.all_bytes = self.image_bytes + self.label_bytes

    def read_binary(self, file_path_list):
        dataset = tf.data.FixedLengthRecordDataset(filenames=file_path_list, record_bytes=self.all_bytes)
        return dataset

    def read_and_decode(self):
        # 获取二进制文件列表
        file_path_list = tf.data.Dataset.list_files("./cifar-10-batches-bin/*.bin")
        # 读取二进制文件 .map(self.build_image).batch(100)
        dataset = self.read_binary(file_path_list)
        images = []
        for element in dataset.as_numpy_iterator():
            images.append(self.build_image(element))
            break
        dataset2 = tf.data.Dataset.from_tensor_slices(images)
        batch_queue = dataset2.batch(100)
        print(batch_queue)

    def build_image(self, element):
        # 二进制解码
        decoded = tf.io.decode_raw(element, tf.uint8)
        # 将目标值和特征值切片
        label = tf.slice(decoded, [0], [self.label_bytes])
        image = tf.slice(decoded, [1], [self.image_bytes])
        # 调整图片形状
        image_reshaped = tf.reshape(image, shape=[self.channels, self.height, self.width])
        # 矩阵转置 self.channels, self.height, self.width -> self.height, self.width,self.channels
        image_trans = tf.transpose(image_reshaped, [1, 2, 0])
        # print(image_trans)
        # 调整图像类型
        image_cast = tf.cast(image_trans, tf.float32)
        print(image_cast)
        return image_cast


if __name__ == '__main__':
    cifar = Cifar()
    cifar.read_and_decode()

2.1.2.6、TFRecords文件
  • TFRecords其实是一种二进制文件,虽然不如其他格式好理解,但是它能更好的利用内存,更方便复制和移动,并且不需要单独的标签文件

    • 使用步骤
      • 获取数据
      • 将数据填入到Example协议内存块(protocol buffer)
      • 将协议内存块序列化为字符串,并且通过tf.io.TFRecordWriter写入到TFRecords文件
      • 文件格式 *.tfrecords
  • Example结构解析

    • tf.train.Example(features=None)

    • tf.train.Features(feature=None)

      • feature:字典数据
    • tf.train.Feature(options)

      • options
        • bytes_list
        • int64_list
    • 例如

          def write_to_tf_records(self, image_s, label_s):
              """
              将样本的特征值与目标值
              :param label_s:
              :param image_s:
              :return:
              """
              with tf.io.TFRecordWriter("cifar-10.tfrecords") as writer:
                  image_iter = image_s.as_numpy_iterator()
                  label_iter = label_s.as_numpy_iterator()
                  for i in range(100):
                      image = image_iter.next().tostring()
                      label = label_iter.next()[0]
                      print(image)
                      print(label)
                      record_bytes = tf.train.Example(features=tf.train.Features(feature={
                          "image": tf.train.Feature(bytes_list=tf.train.BytesList(value=[image])),
                          "label": tf.train.Feature(int64_list=tf.train.Int64List(value=[label])),
                      })).SerializeToString()
                      writer.write(record_bytes)
      
          @staticmethod
          def decode_fn(record_bytes):
              return tf.io.parse_single_example(
                  # Data
                  record_bytes,
                  # Schema
                  {"image": tf.io.FixedLenFeature([], dtype=tf.string),
                   "label": tf.io.FixedLenFeature([], dtype=tf.int64)}
              )
      
          def read_tf_records(self):
              for batch in tf.data.TFRecordDataset(["cifar-10.tfrecords"]).map(self.decode_fn):
                  image = tf.io.decode_raw(batch['image'].numpy(), tf.uint8)
                  # image_reshaped = tf.reshape(image, shape=[self.height, self.width, self.channels])
                  label = batch['label'].numpy()
                  print(image)
                  print(label)
                  # print("x = {image:.4f},  y = {label:.4f}".format(**batch))
      

2.2、神经网络基础

2.2.1、神经网络简介
  • 人工神经网络(ANN)简称为神经网络(NN),是一种模仿生物神经网络(动物的中枢神经系统,特别是大脑)结构和功能的计算模型。经典的神经网络结构包含三个层次的神经网络。分别为输入层输出层隐藏层
    • 其中每层的圆圈代表一个神经元,隐藏层和输出层的神经元有输入的数据计算后输出,输入层的神经元只是输入。
  • 神经网络的特点
    • 每个连接都有个权值
    • 同一层神经元之间没有连接
    • 最后输出结果对应的层也称之为全连接层
  • 感知机(PLA)
    • 感知机是一种最基础的分类模型,类似于逻辑回归,不同的是,感知机的激活函数用的是sign,而逻辑回归是sigmoid。感知机也具有连接的权重和偏置
    • 感知机可以解决的问题
  • https://playground.tensorflow.org/
2.2.2、神经网络原理
2.2.2.1、softmax回归

s o f t m x ( y ) i = e y i ∑ j = 1 n e y i softmx(y)_i = \frac{e^{y_i}}{\sum_{j=1}^{n}e^{y_i}} softmx(y)i=j=1neyieyi

  • 多分类问题
2.2.2.2、交叉熵损失
  • 公式
    H y ′ ( y ) = − ∑ i y i ′ l o g ( y i ) H_{y'}(y) = -\sum_{i}{y_i'}log(y_i) Hy(y)=iyilog(yi)

  • 损失大小

    • 神经网络最后的损失为平均每个样本的损失大小
      • 对所有样本的损失求和取平均值
2.2.2.3、神经网络原理总结
  • 训练过程中计算机会尝试一点点增大或减小每个参数,看其如何减少相比于训练数据集的误差,以望找到最优的权重、偏置参数组合
2.2.2.4、softmax、交叉熵API
  • tf.nn.softmax_cross_entropy_with_logits(labels=None, logits=None,name=None)
    • labels:标签值(真实值)
    • logits:样本加权之后的值
    • return:返回损失值列表
  • tf.reduce_mean(input_tensor)
    • 计算平均值
2.2.3、首页数字识别案例
2.2.3.1 、数据集介绍
  • 特征值
    • 28*28像素
  • 目标值
    • 0~9 的one-hot编码
2.2.3.2 、Mnist数据获取API
  • from tensorflow.examples.tutorials.mnist import input_data
    • mnist = input_data.read_data_sets(path, one_hot=True)
2.2.3.3 、实战:Mnist手写数字识别
  1. 网络设计
  2. 全连接层计算
  3. 流程
  4. 完善模型功能
    1. 如何计算准确率
    2. 增加变量tensorboard显示
    3. 增加模型保存加载
    4. 增加模型预测结果输出
    5. 完整代码

三、卷积神经网络

3.1、卷积神经网络介绍

3.1.1、卷积神经网络与传统多层神经网络对比
  • 传统意义上的多层神经网络是只有输入层、隐藏层、输出层。其中隐藏层的层数根据需要而定,没有明确的理论推导说明到底多少层合适
  • 卷积神经网络CNN,在原来的多层神经网络基础上,加入了更加有效的特征学习部分,具体操作就是在原来的全连接层前面加入了卷积层与池化层。卷积神经网络出现,使得神经网络层数得以加深,深度学习由此而来。
  • 卷积神经网络结构
    • 输入层
    • 隐藏层
      • 卷积层
      • 激活层
      • 池化层
      • 全连接层
    • 输出层
3.1.2、卷积神经网络发展
  • 网络结构加深
  • 加强卷积功能
  • 从分类到检测
  • 新增功能模块
3.1.3、卷积网络ImageNet比赛错误率

3.2、卷积神经网络原理

3.2.1、卷积神经网络结构
  • 卷积层、激活层、池化层、全连接层
  • 卷积神经网络层的作用
    • 卷积层:通过在原始图像上平移来提取特征
    • 激活层:增加非线性分割能力
    • 池化层:减少学习的参数,降低网络的复杂度(最大池化和平均池化)
3.2.2、卷积层(Convolutional Layer)
  • 卷积神经网络中每层卷积层由若干卷积单元(卷积核)组成,每个卷积单元的参数都是通过反向传播算法最佳化得到的。卷积运算的目的是特征提取,第一层卷积层可能只能提取一些低级的特征如边缘、线条和角等层级,更多层的网络能从低级特征中迭代提取更复杂的特征
1、卷积核(Filter)的四大要素
  • 卷积核个数

    • 多个卷积核一起观察,得到多个结果
      • 不同卷积核带的权重和偏置都不一样,即随机初始化参数
  • 卷积核大小

    • 卷积如何计算
      • 输入 5 * 5 *1
      • filter 3 * 3 * 1 步长1
      • 输出 3 * 3* 1
  • 卷积核步长

    • 输入 5 * 5 *1
    • filter 3 * 3 * 1 步长2
    • 输出 2 * 2 * 1
  • 卷积核零填充大小

    • Filter窗口大小和步长可能会导致超出图片像素宽
    • 在像素外围填充一圈值为0的像素
  • 输出大小计算公式

    • 已知输入图片形状、卷积核数量、卷积核大小、移动步长,输出图片形状如何计算
      • 输入体积大小 H1 * W1 * D1
      • 四个超参数
        • Fiter数量K
        • Filter大小F
        • 步长S
        • 零填充大小P
      • 输出体积大小 H2 * W2 * D2
        • H2 =
        • W2 = (W1 - F + 2P)/S + 1
        • D2 = K
  • 多通道图片(彩色)如何观察

    • 输入 7 * 7 * 3
    • filter 3 * 3 * 3 + bias 步长2 ,2个Filter
    • 输出 3 * 3 * 2
2、卷积网络API
  • tf.nn.conv2d(input=,filters=,strides=,padding=,name=)
    • input
      • 输入图像
      • 要求:shape=[batch, heigh,width, channel],类型为float32,64
    • filters
      • weight
        • 变量:shape=[F, F, D1, K]
    • strides
      • 步长S
      • [1, S, S, 1]
    • padding
      • “SAME”:越过边缘取样(零填充)
      • “VALID”:不越过边缘取样
3、小结
  • 零填充 <=> 固定输出大小

  • 卷积核大小一般1 * 1,3 * 3,5 * 5,步长一般为1

  • 每个过滤器带有若干权重和1个偏置

3.2.3、激活函数
  • 随着神经网络的发展,大家发现原有的sigmoid等激活函数并不能达到好的效果,所以采取新的激活函数
  • sigmoid函数缺点
    • 计算量相对大
    • 梯度消失
    • 输入值的范围[-6,6]
1、Relu激活函数

R e L U = m a x ( 0 , x ) ReLU = max(0,x) ReLU=max(0,x)

  • Relu优点
    • 有效解决梯度消失问题
    • 计算速度非常快
    • 图像没有负的像素值
  • API
    • tf.nn.relu(features, names=None)
      • features:卷积后加上偏置的结果
3.2.4、池化层
  • Pooling层主要的作用是特征提取,通过去掉Feature Map中不重要的样本,进一步减少参数数量。Pooling的方法很多,通常采用最大池化
    • max_polling:取池化窗口的最大值
    • avg_polling:取池化窗口的平均值
  • 池化层计算
    • 池化层也有窗口大小以及移动步长,计算公式跟卷积公式一样
      • H2 = (H1 - F + 2P)/S + 1
      • W2 = (W1 - F + 2P)/S + 1
      • D2 = K
  • 池化层API
    • tf.nn.max_pool(“”, ksize=,strides=,padding=,name=)
      • value:4-D Tensor形状[batch, height, width, channels]
        • channel:filter数量
      • ksize:池化窗口大小,[1, ksize, ksize, 1]
      • strides:步长大小
        • [1,S,S,1]
      • padding:“SAME”,“VALID”
3.2.5、全连接层
  • 卷积层和池化层相当于做特征工程,最后的全连接层是在整个卷积神经网络中起到“分类器”的作用

3.3、案例:手写数字识别

3.3.1、网络设计
  • 第一层
    • 卷积层 32filter 大小 5 * 5 步长1 padding=“SAME”
    • 激活 Relu
    • 池化 大小2*2 步长2
  • 第二层
    • 卷积层 64filter 大小 5 * 5 步长1 padding=“SAME”
    • 激活 Relu
    • 池化 大小2*2 步长2

3.5、网络的优化和改进

  • 初始化参数大小调整
    • 模型参数大小缩小
  • 使用改进版的SGD算法
  • 对于深度网络使用batch normalization 或者droupout层

3.6、

3.4、案例:验证码识别

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
深度学习笔记v5是一本关于深度学习的学习资料,下面我将用300字来回答有关这本笔记的内容。 深度学习是机器学习领域的一个重要分支,它主要研究模拟人脑神经网络的算法和模型,用于实现复杂的学习任务。深度学习在图像识别、语音识别和自然语言处理等领域取得了很多重要的突破,成为了人工智能领域的热点研究方向。 深度学习笔记v5中,首先介绍了深度学习的基本概念和原理。笔记详细解释了神经网络结构、前向传播、反向传播以及梯度下降等基本概念和算法。这些内容帮助读者理解深度学习的基本原理和工作机制。 接着,笔记介绍了常用的深度学习框架,如TensorFlow和PyTorch。这些框架提供了丰富的工具和函数,使得深度学习的开发变得更加简单和高效。笔记详细介绍了如何使用这些框架进行模型训练和评估。 此外,笔记还包含了一些深度学习的经典应用案例。这些案例涵盖了图像分类、目标检测、语音识别等多个领域。通过这些案例,读者可以深入了解深度学习在实际问题中的应用,并学习如何利用深度学习解决现实世界中的复杂任务。 最后,笔记还提供了大量的代码示例和练习题,帮助读者巩固所学的知识。通过实践,读者可以更好地理解深度学习的原理和应用。 总而言之,深度学习笔记v5是一本系统而全面的学习资料,适合对深度学习感兴趣的读者。通过阅读这本笔记,读者可以了解深度学习的基本概念和原理,掌握常用的深度学习框架,以及应用深度学习解决实际问题的方法。希望这本笔记能够对读者在深度学习领域的学习和研究有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值