当前位置: 首页 > news >正文

查找网站备案信息做网站协议怎么签

查找网站备案信息,做网站协议怎么签,做液氮冰淇淋店网站,深圳做小程序开发哪家好打开深度学习的锁 导言PS#xff1a;神经网络的训练过程一、导入的包和说明二、数据的预处理2.1 数据集说明2.2 数据集降维度并且转置2.3 数据预处理完整代码 三、逻辑回归3.1 线性回归函数公式3.2 sigmoid函数公式 四、初始化函数五、构建逻辑回归的前向传播和后向传播5.1 损… 打开深度学习的锁 导言PS神经网络的训练过程一、导入的包和说明二、数据的预处理2.1 数据集说明2.2 数据集降维度并且转置2.3 数据预处理完整代码 三、逻辑回归3.1 线性回归函数公式3.2 sigmoid函数公式 四、初始化函数五、构建逻辑回归的前向传播和后向传播5.1 损失函数5.2 前向传播5.3 后向传播5.3.1 梯度下降算法 5.4 前向传播和后向传播完整代码 六、代码逐步拟合6.1 运行梯度下降更新w和b6.2 实现预测函数计算数据转化的值6.3 模型调用函数6.4 完整代码和测试6.5 再玩一下好的 写在后面的话 导言 本篇知识背景来源于吴恩达教授的DeepLearning课程作业–第二节有兴趣的同学可以自行搜索。 博客所用到的数据集和测试代码已经公开Github 这篇博客本质内容吴恩达教授的DeepLearning的课程作业第二节是题解。个人觉得作为神经网络入门练习是一个很棒的契机故以此记录。 博客中包含一点Python向量化Vectorization和导数Derivative及链式法则Chain rule的内容如果看不明白也没关系别紧张也别怕。只需要明白以下的内容即可 1.Python向量化Vectorization 一种技术就是代替Python的for循环跑的比for循环快。 2.导数Derivative及链式法则Chain rule 如果你知道 AB也就是知道A增加导致B增加它可以告诉我们它们之间是如何互相影响的。 这篇博客中用到的主要是NumPy库中的函数但是我不会详细的去讲解每一个函数的功能就是使用。 还有一点很重要如果你是科班之前只是说过“机器学习”、“深度学习”、“模型”这类词汇感觉中间的处理很黑盒但是不了解到底是什么。 那么这些很重要 所谓模型是由很多同类型的数据产生的一个组参数适合 的函数得到这个函数方便处理其它同类型数据。 模型不是软件不是软件不是软件 所谓学习通过数据的输入–得到模型的预测值将预测值和实际的标签比较标签和预测值的差异称为损失。通过之间的损失自动调整公式里面参数最终找那个可以让损失最小的、合适的公式的参数 不是单纯的输入数据和输入的标签学习映射关系 好了让我们开始吧。 PS神经网络的训练过程 放此图在这里为了快速认识也为了需要的时候快速查找。初次看的时候看不懂没关系可以先看下面的内容。 一、导入的包和说明 关于头文件的说明 #1.导入序列化必要函数 import numpy as np#2.导入生成图片要的包 # 在 Python 中导入 matplotlib 库的 pyplot 模块并为其指定一个简称 plt 的语句。matplotlib 是一个非常流行的 Python 数据可视化库它提供了一套全面的绘图工具来制作各种静态、动态或交互式的图形。 # pyplot 是 matplotlib 的一个子模块通常被认为是该库的核心。它提供了一个类似于 MATLAB 的绘图界面使得创建图形变得非常简单。 import matplotlib.pyplot as plt#导入针对数据格式的包,本篇中用到的数据集格式是.h5. # h5py 是一个 Python 库它提供了一种高效的方式来读取和写入 HDF5(h5) 格式的文件。 # HDF5Hierarchical Data Format version 5是一个流行的数据存储格式常用于大型数据集如科学计算或深度学习中的训练数据。 # HDF5 文件可以包含大量的数据集并支持高效的并行IO操作它提供了一种结构化的方式来存储数据其中数据可以被组织为不同的组和数据集。 import h5py#从lr_utils文件或者称为模块每一个py文件就是一个模块导入函数 from lr_utils import load_dataset二、数据的预处理 2.1 数据集说明 在给出的文件lr_utils 中的load_dataset函数是对训练集和测试集的预处理并且已经封装好了 import numpy as np import h5pydef load_dataset():train_dataset h5py.File(datasets/train_catvnoncat.h5, r) train_set_x_orig np.array(train_dataset[train_set_x][:]) # your train set features#保存的是训练集里面的图像数据本训练集有209张64x64的图像。train_set_y_orig np.array(train_dataset[train_set_y][:]) # your train set labels#保存的是训练集的图像对应的分类值【0 | 1】0表示不是猫1表示是猫。test_dataset h5py.File(datasets/test_catvnoncat.h5, r)test_set_x_orig np.array(test_dataset[test_set_x][:]) # your test set features#保存的是测试集里面的图像数据本训练集有50张64x64的图像。test_set_y_orig np.array(test_dataset[test_set_y][:]) # your test set labels#保存的是测试集的图像对应的分类值【0 | 1】0表示不是猫1表示是猫。classes np.array(test_dataset[list_classes][:]) # the list of classes#保存的是以bytes类型保存的两个字符串数据数据为[b’non-cat’ b’cat’]。train_set_y_orig train_set_y_orig.reshape((1, train_set_y_orig.shape[0]))test_set_y_orig test_set_y_orig.reshape((1, test_set_y_orig.shape[0]))return train_set_x_orig, train_set_y_orig, test_set_x_orig, test_set_y_orig, classes我们直接在主文件里面使用即可 import numpy as np import matplotlib.pyplot as plt import h5py from lr_utils import load_dataset#全局变量 train_set_x_orig, train_set_y, test_set_x_orig, test_set_y, classesload_dataset()现在我们拥有了数据集和测试集合可以使用X.shape的方法查看一下它们的维度 print(train_set_x_orig.shape) #(209, 64, 64, 3) 维度说明训练数据集是由209个 64*64的3色域图片组成 print(train_set_y_orig.shape) #(1, 209) 标签,1维度的209个标签我们注意到训练集是一个209,64,64,3维度的矩阵那么这个是什么呢 其实就是保存的209个大小为64*64像素的RGB的图片 举个例子 这里有一条可爱的猫猫的图片,假设它的大小是 5*5 个像素。(图片来源图片) 我们知道每一个图片在计算机中存储的形式都是由红色R、绿色G、蓝色B三个底色图片构成 这三个底色图片的参数都不一样因为不一样所以才可以构成千颜万色。 对于当前的步骤我们不需要关心每一个矩阵中的参数是怎么样的。 我们只需要知道一个图片在计算机中完整的像素的个数是高像素 X 宽像素 X 3 所以一个图片的矩阵向量的表现形式就是 [ 高像素 , 宽像素 , 3 ] 这条猫猫的矩阵向量的表现形式是[5,5,3] 而在本题中作为数据集自然要有样本的个数所以我们的train_set_x_orig矩阵多了一个209,代表样本的个数。 print(train_set_x_orig.shape) #(209, 64, 64, 3) 维度说明训练数据集是由209个 64*64的3色域图片组成为了证明我没有胡说我们打印两个数据集中的图片看看 第一个高贵的瓦坎达吉祥物 #打印测试单个 index25 plt.imshow(train_set_x_orig[index]) plt.show() # print(label:str(train_set_y_orig[:,index]))第二个非猫 #打印测试单个 index26 plt.imshow(train_set_x_orig[index]) plt.show() # # print(label:str(train_set_y_orig[:,index]))2.2 数据集降维度并且转置 好了将接下来我们需对于数据集降维度并且转置。 为什么这样做呢 为了方便数据输入到模型我们希望统一训练集和测试集的格式。 我们刚刚提到的,测试了两个数据集合的维度,可以看到它们是不匹配的 print(train_set_x_orig.shape) #(209, 64, 64, 3)表示样本个数的209在第一维度之后有三个维度的数据。 print(train_set_y_orig.shape) #(1, 209) 表示标签个数的209在第二个维度之前有一个维度的数据。所以我们希望将第一个数据集的格式转化成和第二个数据集合一样的个格式。 我们的目的是希望将 A(a,b,c,d) 的矩阵变成 A(b * c * d , a) 矩阵,公式为 X_flatten X.reshape(X.shape[0],-1).T 代码如下 #Dimensionally reduce and Transpose the Training Data_set # print(train_set_x_orig.shape) #(209, 64, 64, 3) train_set_x_flatten train_set_x_orig.reshape(train_set_x_orig.shape[0],-1).T # print(train_set_x_flatten.shape) #(12288, 209) #Dimensionally reduce and Transpose the Testing Data_Set # print(test_set_x_orig.shape) #(50, 64, 64, 3) test_set_x_flatten test_set_x_orig.reshape(test_set_x_orig.shape[0],-1).T # print(test_set_x_flatten.shape) #(12288, 50)下一步我们希望标准化数据将每一行的值控制在0-1之间。标准化的方法有很多但是因为所有的都是图片的RGB所以可以直接除以255 train_set_xtrain_set_x_flatten/255 test_set_xtest_set_x_flatten/255这个时候有小朋友就会问了“ 前面不是已经将除了”个数“以外的数据都相乘了吗只除以一个255够了吗” 当然因为reshape 函数允许我们重新组织数组的维度但它 不会 更改数组元素的顺序或值。 也就是说只是维度被整合了元素里面的值和内容还是没有改变。 并且我们都知道在矩阵计算中乘除一个数就算对矩阵内的所有元素进行乘除所以只写一个/225就够啦 2.3 数据预处理完整代码 #获取数据集 train_set_x_orig, train_set_y, test_set_x_orig, test_set_y, classesload_dataset()# 打印测试单个 index25 plt.imshow(train_set_x_orig[index]) plt.show() # print(label:str(train_set_y_orig[:,index]))#降维度 # print(train_set_x_orig.shape) #(209, 64, 64, 3) train_set_x_flatten train_set_x_orig.reshape(train_set_x_orig.shape[0],-1).T # print(train_set_x_flatten.shape) #(12288, 209) #Dimensionally reduce and Transpose the Testing Data_Set # print(test_set_x_orig.shape) #(50, 64, 64, 3) test_set_x_flatten test_set_x_orig.reshape(test_set_x_orig.shape[0],-1).T # print(test_set_x_flatten.shape) #(12288, 50) #将每一行的值控制在0-1之间因为所有的都是图片的RGB所以可以除以255 train_set_xtrain_set_x_flatten/255 test_set_xtest_set_x_flatten/255三、逻辑回归 数据处理的部分完成了接下来就是构建神经网络。我们要处理的是二分类问题而 “逻辑回归” 是处理二分问题的一个算法。 逻辑回归的目标实际上是找到一个决策边界然后根据样本点相对于这个边界的位置来分类对于线性逻辑回归这个决策边界是一条直线在二维空间中或一个超平面在更高的维度中这取决于特征的数量。 就是说找一条线将数据划分为两个部分。 如果维度高的话是找一个面来划分 对于逻辑回归的函数我们可以理解为 逻辑回归函数线性回归函数 sigmoid函数 3.1 线性回归函数公式 Z z ( i ) w T ⋅ x ( i ) b Z z^{(i)} w^T \cdot x^{(i)} b Zz(i)wT⋅x(i)b x i x^i xi: 第i个样本的特征向量w: 权重向量表示当前 x i x^i xi的权重比权重用于决定决策边界怎么画w.T: 是w的转置我们为了计算w与x的“点乘”要求w的行向量 x的列向量.如果你的 w 向量本来就是一个行向量并且它的长度列数与 x 向量的长度行数相同不需要再进行转置但是权重向量和特征向量通常都被定义为列向量这是一种约束。b: 这是偏置项它是一个常数。 z i z^i zi: 第i个样本的线性输出。输入一个 x i x^i xi会得到一个 z i z^i zi 3.2 sigmoid函数公式 σ ( z ) 1 1 e − z \sigma(z) \frac{1}{1 e^{-z}} σ(z)1e−z1​ 或者,嵌套线性回归函数 y ^ i 1 1 e − ( w T ⋅ x ( i ) b ) \hat{y}^i \frac{1}{1 e^{-( w^T \cdot x^{(i)} b)}} y^​i1e−(wT⋅x(i)b)1​ 关于sigmoid函数我们需要知道 它是一种激活函数激活函数是神经网络中的一个重要组成部分它决定一个神经元是否应该被“激活”或“触发”。具体地说激活函数定义了每个神经元的输出与其输入之间的关系。它为神经网络引入了非线性因素使得网络能够学习并执行更复杂的任务。它的输出范围[0,1]它的图像是这样 当我们将一个 x i x^i xi输入到sigmoid函数中会得到一个 y ^ \hat{y} y^​或者 y ^ i \hat{y}^i y^​i ,它是由 x i x^i xi生成的和当前标签 y i y^i yi同类型的值这也是为什么用hat/y表示而不是用别的字母 它是0和1之间的概率值表示正类也就是1的预测概率。 在这里 y ^ i 是模型对输入  x i 的预测输出而  y i 是实际的标签或真实值。 \text{在这里} \hat{y}^i \text{ 是模型对输入 } x^i \text{ 的预测输出而 } y^i \text{ 是实际的标签或真实值。} 在这里y^​i 是模型对输入 xi 的预测输出而 yi 是实际的标签或真实值。 我们希望  x i 生成的预测 y ^ i 尽可能接近  x i 的标签  y i 。 \text{我们希望 } {x}^i \text{ 生成的预测} \hat{y}^i \text{尽可能接近 }{x}^i \text{的标签 }y^i \text{。} 我们希望 xi 生成的预测y^​i尽可能接近 xi的标签 yi。 为了得到一个明确的分类预测0或1可以设定一个阈值通常为0.5。如果 y ^ \hat{y} y^​大于0.5则预测为1否则为0。 所以在这个公式中为了让 y ^ \hat{y} y^​ 趋近于1我们便需要让 w T ⋅ x ( i ) b w^T \cdot x^{(i)} b wT⋅x(i)b的值尽可能的大。 所以逻辑回归的目标就是找到合适的 w w w和 b b b 好了概念理清了我们开始写代码 对于代码关于线性函数我们一会可以使用np里面的函数直接计算所以只需要写sigmoid的函数即可 def sigmoid(z): #z:传入的线性函数的结果值s1/(1np.exp(-z))return s #$\hat{y}$下一步既然要找 w w w和 b b b我们就应该写一个初始化函数先给 w w w和 b b b 赋默认值。 四、初始化函数 很简单直接上代码 def initialize_zeros(dim):#为了创建可以和训练集X计算的权重矩阵w#dim:传入的数据集的第一个向量坐标X.shape[0]#一些博客里面会这样写#wnp.zeros(shape(dim,1))#这样做的目的是将所有的值用0填充但是这样也许会导致一个“对称性”问题#当你这样初始化权重并使用它们在神经网络中时每一层的所有神经元都会有相同的输出。#因此当你进行反向传播时所有神经元都会收到相同的梯度。这将导致所有的权重都更新为相同的值。无论网络有多少神经元它们都会表现得像一个神经元这极大地限制了网络的容量和表达能力。#所以我们使用随机w0.01*np.random.rand(dim,1)#乘以0.01是为了确保初始化的权重值很小。b0#使用断言来检测是正确assert(w.shape(dim,1))assert(isinstance(b,float) or isinstance(b,int))return (w,b)初始化参数的函数已经构建好了现在就可以执行“前向”和“后向”传播步骤来学习参数。 五、构建逻辑回归的前向传播和后向传播 神经网络或者深度学习模型单次的训练过程有四个阶段 前向传播给当前数据 x i x^i xi根据算法当前我们用的是sigmoid函数输出一个结果 y ^ i \hat y^i y^​i计算机损失得到前向传播的预测 y ^ i \hat y^i y^​i以后我们会评估“预测与我们给定的标签 y i y^i yi之间的差异。这个差异通常称为“损失”或“误差”后向传播基于前面计算的损失模型会计算每个参数的梯度以知道如何更好地更新参数来提高预测。这个步骤就是告诉模型“为了减少预测误差你应该这样调整你的参数w和b。”更新参数: 在知道了如何更新参数之后实际更新参数。 到目前为之我们已经完成了前两步的基本实现和理论概括。我将会在这个章节将它们进行组合实现完整的前向传播和后向传播。 不过在此之前我们还需要引入一个东西损失函数 5.1 损失函数 很久很久以前在一座威严耸立的山上。一群数学家在给一群哲学家分完筷子以后闲的无聊。这个时候突然有人想到了一个问题 有没有什么办法可以让标签 ( y i {y^i} yi) 为 1 的 x i {x^i} xi 的预测值 ( y ^ i \hat{y}^i y^​i) 趋近于 1 有没有什么办法可以让标签 ( y i {y^i} yi) 为 0 的 x i {x^i} xi 的预测值 ( y ^ i \hat{y}^i y^​i) 趋近于 0 这个时候有一个拿到 两根筷子 的哲学家说简单啊你让 可以让标签 ( y i {y^i} yi) 为 1 的 x i {x^i} xi 的预测值 ( y ^ i \hat{y}^i y^​i) 不趋近于 0 可以让标签 ( y i {y^i} yi) 为 0 的 x i {x^i} xi 的预测值 ( y ^ i \hat{y}^i y^​i) 不趋近于 1 在把这个哲学家祭天以后一个数学家仔细琢磨这句话说“不如这样吧我们可以想一个公式在公式里面同时输入 y i {y^i} yi和 y ^ i \hat{y}^i y^​i。如果这两个的值很相近呢就让这个公式的输出的值小一点。如果不相近呢就让它的输出大一点。” “那我们用 对数log 吧” 另一个数学家说道。 “既然不相近我们假设这个公式的输出为 L o s s Loss Loss吧代表 “损失” 如果输入的 y i {y^i} yi为 1 我就让 L o s s − log ⁡ ( y ^ ( i ) ) Loss -\log(\hat{y}^{(i)}) Loss−log(y^​(i)) 这样如果 y ^ i \hat{y}^i y^​i接近 0 时S会特别大反之会特别小。 如果输入的 y i {y^i} yi为 0 我就让 L o s s − log ⁡ ( 1 − y ^ ( i ) ) Loss -\log(1 - \hat{y}^{(i)}) Loss−log(1−y^​(i)) 这样如果 y ^ i \hat{y}^i y^​i接近 1 时S会特别大反之会特别小。” “那我们把它们结合一下吧成为一个公式。同时让这两个公式添加两个非0即1的相反的乘数。虽然是一个公式但是同时只有一半可以用。“ “我看就用 y i {y^i} yi 和 1 − y i 1-{y^i} 1−yi 吧这两个不是标签么非0即1” “太棒了让我再来添加一个帅气的符号吧把它变成 L o s s L ( y , y ^ ) − [ y log ⁡ ( y ^ ) ( 1 − y ) log ⁡ ( 1 − y ^ ) ] LossL(y, \hat{y}) -[y \log(\hat{y}) (1 - y) \log(1 - \hat{y})] LossL(y,y^​)−[ylog(y^​)(1−y)log(1−y^​)]” “太帅了!!!,我们给它取一个名字吧同时找一个帅气的翻译者把它翻译词让人 望!而!生!畏! 的中文吧” “那就叫 二元交叉熵损失函数Binary Cross-Entropy Loss也称为log loss 吧” “既然有处理单个数据的函数了那么我们再改善一下吧让它可以处理多个数据吧” “这好办呀假设有 M M M个数据我们把每一个单一的数据结果加起来然后再除以 M M M不就好了吗” “既然结果依赖于 y ^ ( i ) \hat{y}^{(i)} y^​(i)和 y ( i ) {y}^{(i)} y(i)同时 y ( i ) {y}^{(i)} y(i)和 x ( i ) {x}^{(i)} x(i)是给定的不能修改那么可以说结果决度定于 y ^ ( i ) \hat{y}^{(i)} y^​(i)” “ y ^ ( i ) \hat{y}^{(i)} y^​(i)不是来源于 y ^ ( i ) 1 1 e − ( w T ⋅ x ( i ) b ) \hat{y}^(i) \frac{1}{1 e^{-( w^T \cdot x^{(i)} b)}} y^​(i)1e−(wT⋅x(i)b)1​吗而且刚刚不是有个高大威猛帅气的男生说 逻辑回归的目标就是找到合适的 w w w和 b b b 吗那我们干脆直接用 w w w和 b b b作表示吧那不就是…” J ( w , b ) 1 m ∑ i 1 m L ( y ( i ) , y ^ ( i ) ) J(w, b) \frac{1}{m} \sum_{i1}^{m} \text{L}(y^{(i)}, \hat{y}^{(i)}) J(w,b)m1​i1∑m​L(y(i),y^​(i)) 这就是损失函数Cost Function / Loss Function 在深度学习中我们需要找合适的 w w w和 b b b尽可能的缩小 J ( w , b ) J(w,b) J(w,b) 5.2 前向传播 通过我们现在的知识可以构建前向传播了。 前向传播Forward Propagation 是神经网络中的一个过程其中输入数据从输入层流经网络的每一层直到最后生成输出。在这个过程中每一层的神经元接收上一层的输出对于第一层接收输入数据并通过加权和以及激活函数产生该层的输出。这些输出随后被传递到下一层直至达到输出层。 前向传播的目的是基于当前的参数权重和偏置和输入数据来计算网络的输出。当得到网络的输出之后我们可以将它与真实的目标或标签值进行比较从而计算损失。 代码 #前向传播计算损失 def propagate(w,b,X,Y): #传入的参数# w:权重向量维度为[X.shape[0],1]#每一个元素的值随机 参见初始化函数#w的第一个维度应该等于X.shape[0]为什么因为w.T也就是[1,X.shape[0]]要X进行点乘 参见线性回归函数# b偏差一个常数# X输入的矩阵当前为 (12288, 209)# Y标签矩阵 当前为1,209 #返回的参数#cost:当前一轮训练完成后计算得到的损失值的平均,单个的点相较于决策边界的成本的总和的平均mX.shape[1] #X的第二个参数也就是样本的总个数 #Zw.T*Xb #线性函数 Asigmoid(np.dot(w.T,X)b) #sigmoid函数将线性函数集成了 #此时这里A是一个矩阵里面的内容是模型的预测值#使用向量化以后的组合 cost(-1/m)*np.sum(Y*np.log(A) (1-Y)*(np.log(1-A))) #注意因为计算机的时候参与了Y矩阵所以这个时候cost里面有一个下标为1,对于Y1,209来说这个1是确保Y是一个矩阵但是对于cost这个1是无用的我们需要移除 costnp.squeeze(cost) return cost5.3 后向传播 现在我们已经知道了“损失”我们便可以通过“损失”的大小来反向的调整 w w w和 b b b使得 z w T ⋅ x b z w^T \cdot x b zwT⋅xb 画出来的决策边界可以尽可能的拟合所有的点。 怎么做呢 使用梯度下降 5.3.1 梯度下降算法 梯度下降算法它的公式为 对于 w w w的更新 1求损失函数 J J J关于权重 w w w的偏导数 ∂ J ∂ w 1 m X ( Y ^ − Y ) T \frac{\partial J}{\partial w} \frac{1}{m} X (\hat{Y} - Y)^T ∂w∂J​m1​X(Y^−Y)T 2:新的 w w w等于当前 w − a w-a w−a倍的损失函数 J J J关于权重 w w w的偏导数 w w − α ∂ J ∂ w w w - \alpha \frac{\partial J}{\partial w} ww−α∂w∂J​ 对于 b b b的更新 1求损失函数 J J J关于权重 b b b的偏导数 ∂ J ∂ b 1 m ∑ i 1 m ( y ^ ( i ) − y ( i ) ) \frac{\partial J}{\partial b} \frac{1}{m} \sum_{i1}^{m} (\hat{y}^{(i)} - y^{(i)}) ∂b∂J​m1​i1∑m​(y^​(i)−y(i)) 2:新的 b b b等于当前 b − a b-a b−a倍的损失函数 J J J关于权重 b b b的偏导数 b b − α ∂ J ∂ b b b - \alpha \frac{\partial J}{\partial b} bb−α∂b∂J​ 这些公式有兴趣的小伙伴可以自行推导一下方法很简单使用链式法则。 为什么要求导呢为什么求导数可以反推呢 别问用就行。管它意大利的还是东北山里的能响就好炮。 5.4 前向传播和后向传播完整代码 结合前向传播的片段我们现在可以写出本章完整的代码 注意由于我们还需要将学习率参与到运算中所以这个函数返回的是dw和db的需要更新多少并不是真的已经更新完的值。 def propagate(w,b,X,Y):#传入的参数# w:权重向量维度为[X.shape[0],1]#每一个元素的值随机 参见初始化函数#w的第一个维度应该等于X.shape[0]为什么因为w.T也就是[1,X.shape[0]]要X进行点乘 参见线性回归函数# b偏差一个常数# X输入的矩阵当前为 (12288, 209)# Y标签矩阵 当前为1,209#返回的参数#cost:当前一轮训练完成后计算得到的损失值的平均,单个的点相较于那条线的成本的总和的平均#dw:后向传播以后w需要改变多少#db:后向传播以后b需要改变多少mX.shape[1] #X的第二个参数也就是样本的总个数#前向传播:也就是执行一次逻辑回归和损失计算也就是执行那三个函数#Zw.T*Xb #线性函数Asigmoid(np.dot(w.T,X)b) #sigmoid函数将线性函数集成了#此时这里A是一个矩阵里面的内容是模型的预测值#使用向量化以后的组合 cost(-1/m)*np.sum(Y*np.log(A) (1-Y)*(np.log(1-A)))#注意因为计算机的时候参与了Y矩阵所以这个时候cost里面有一个下标为1,对于Y1,209来说这个1是确保Y是一个矩阵但是对于cost这个1是无用的我们需要移除costnp.squeeze(cost)#反向传播:计算w和b需要改变多少#为了计算w和b我们需要使用梯度下降算法它的公式是# w w - 学习率 * 损失函数对于w的导数dzA-Ydw (1/m) * np.dot(X,dz.T)db (1/m) * np.sum(dz)#确保数据是否正确assert(dw.shape w.shape)assert(db.dtype float)#断言会失败导致程序抛出一个 AssertionError 异常。assert(cost.shape ())#创建一个字典把dw和db保存起来。grads{dw:dw,db:db}return (grads,cost)六、代码逐步拟合 现在我们已经有了实现所有功能的代码我们使用一些聚合函数将它们逐步聚合。 这样做的好处有很多最主要的是如果代码出现问题,我们不用盯着一大块代码段查找bug…同时作为学习者分块写代码可以方便我们以后查阅和复习 6.1 运行梯度下降更新w和b #通过最最小化成本函数J来学习w和b def optimize (w,b,X,Y,num_itertions,learning_rate,print_cost False):# 此函数通过运行梯度下降算法来优化w和b# 参数# w - 权重大小不等的数组num_px * num_px * 31# b - 偏差一个标量# X - 维度为num_px * num_px * 3训练数据的数量的数组。# Y - 真正的“标签”矢量如果非猫则为0如果是猫则为1矩阵维度为(1,训练数据的数量)# num_iterations - 优化循环的迭代次数# learning_rate - 梯度下降更新规则的学习率,就是那个阿尔法# print_cost - 每100步打印一次损失值# 返回# params - 包含权重w和偏差b的字典# grads - 包含权重和偏差相对于成本函数的梯度的字典# 成本 - 优化期间计算的所有成本列表将用于绘制学习曲线。# 提示# 我们需要写下两个步骤并遍历它们# 1计算当前参数的成本和梯度使用propagate。# 2使用w和b的梯度下降法则更新参数。costs[]for i in range (num_itertions):grads, cost propagate(w,b,X,Y)dw grads[dw]db grads[db]#公式w w-learning_rate *dwb b-learning_rate *db#记录成本if i %100 0:costs.append(cost)#打印成本数据if (print_cost) and (i % 100 0):print(迭代的次数: %i 误差值 %f % (i,cost))#创建字典保存w和bparams{w:w,b:b}grads{dw:dw,db:db}return (params,grads,costs)# print(测试optimize) # #([[1],[2]])一维的数组有两个元素[1]和[2] # w,b,X,Ynp.array([[1],[2]]), 2 , np.array([[1,2],[3,4]]), np.array([[1,0]]) # params,grads,costsoptimize(w,b,X,Y,num_itertions100,learning_rate 0.009,print_cost False) # print (w str(params[w])) # print (b str(params[b])) # print (dw str(grads[dw])) # print (db str(grads[db]))6.2 实现预测函数计算数据转化的值 现在optimize函数会输出已学习的w和b的值我们可以使用w和b来预测数据集X的所生成的标签预测标签是0还是1。 我们要实现预测函数。计算预测有两个步骤 1.计算 Y A σ ( w T X b ) Y ^ A σ ( w^TX b ) YAσ(wTXb) 2.选定sigmoid函数的阈值将 a a a变为0如果激活值0.5或者1如果激活值0.5, a a a 表示神经元的激活值, A A A 是sigmoid激活函数 σ σ σ 的输出矩阵。 def predict(w,b,X):#使用学习逻辑回归参数logisticw,b预测标签是0还是1,# 参数# w - 权重大小不等的数组num_px * num_px * 31# b - 偏差一个标量# X - 维度为num_px * num_px * 3训练数据的数量的数组。# 返回# Y_prediction - 包含X中所有图片的所有预测【0 | 1】的一个numpy数组向量mX.shape[1] #图片的数量Y_prediction np.zeros((1,m)) #创建都是0的矩阵1行m列ww.reshape(X.shape[0],1) #将w转为一个图片参数的累乘维度为1#预测猫在图片中出现的概率Asigmoid(np.dot(w.T,X)b)for i in range(A.shape[1]):#将概率a[0,1]转化为实际预测的p[0.i]Y_prediction[0,i] 1 if A[0,i] 0.5 else 0#使用断言assert(Y_prediction.shape(1,m))return Y_prediction # print(测试predict) # w, b, X, Y np.array([[1], [2]]), 2, np.array([[1,2], [3,4]]), np.array([[1, 0]]) # print(predictions str(predict(w, b, X)))6.3 模型调用函数 就目前而言我们基本上把所有的东西都做完了现在我们要把这些函数统统整合到一个model()函数中届时只需要调用一个model()就基本上完成所有的事了。 def model(X_train , Y_train , X_test , Y_test , num_iterations 2000 , learning_rate 0.5 , print_cost False):w , b initialize_zeros(X_train.shape[0])parameters , grads , costs optimize(w , b , X_train , Y_train,num_iterations , learning_rate , print_cost)#从字典“参数”中检索参数w和bw , b parameters[w] , parameters[b]#预测测试/训练集的例子Y_prediction_test predict(w , b, X_test)Y_prediction_train predict(w , b, X_train)#打印训练后的准确性print(训练集准确性 , format(100 - np.mean(np.abs(Y_prediction_train - Y_train)) * 100) ,%)print(测试集准确性 , format(100 - np.mean(np.abs(Y_prediction_test - Y_test)) * 100) ,%)d {costs : costs,Y_prediction_test : Y_prediction_test,Y_prediciton_train : Y_prediction_train,w : w,b : b,learning_rate : learning_rate,num_iterations : num_iterations }return d # print(测试model) # #这里加载的是真实的数据请参见上面的代码部分。 # d model(train_set_x, train_set_y_orig, test_set_x, test_set_y_orig, num_iterations 2000, learning_rate 0.005, print_cost True) # #绘制图 # costs np.squeeze(d[costs]) # plt.plot(costs) # plt.ylabel(cost) # plt.xlabel(iterations (per hundreds)) # plt.title(Learning rate str(d[learning_rate])) # plt.show()6.4 完整代码和测试 以下是完整代码 #所谓模型就是一个组参数适合的公式 #所谓学习就是找那个合适的参数#导入序列化必要函数 import numpy as np#导入生成图片要的包 import matplotlib.pyplot as plt # 是在 Python 中导入 matplotlib 库的 pyplot 模块并为其指定一个简称 plt 的语句。matplotlib 是一个非常流行的 Python 数据可视化库它提供了一套全面的绘图工具来制作各种静态、动态或交互式的图形。 # pyplot 是 matplotlib 的一个子模块通常被认为是该库的核心。它提供了一个类似于 MATLAB 的绘图界面使得创建图形变得非常简单。#导入针对数据格式的包 import h5py # import h5py 是 Python 中引入 h5py 库的命令。 # h5py 是一个 Python 库它提供了一种高效的方式来读取和写入 HDF5 格式的文件。 # HDF5Hierarchical Data Format version 5是一个流行的数据存储格式常用于大型数据集如科学计算或深度学习中的训练数据。 # HDF5 文件可以包含大量的数据集并支持高效的并行IO操作它提供了一种结构化的方式来存储数据其中数据可以被组织为不同的组和数据集。#从lr_utils文件或者称为模块每一个py文件就是一个模块导入函数 from lr_utils import load_dataset#load_dataset函数是对训练集合和测试集合的预处理并且已经封装好了提取就可以 train_set_x_orig,train_set_y_orig,test_set_x_roig,test_set_y_orig,classesload_dataset()#classes是一个字段就是将 0 表示非猫non-cat图片1 表示猫cat文字说明#查看一下两个数据集有多少数据几个维度print(train_set_x_orig.shape) #(209, 64, 64, 3) 训练集209行的后面那三个维度的矩阵 print(train_set_y_orig.shape) #(1, 209) 训练集标签1行的209个数据 训练数据集是由209个 64*64的3色域图片组成print(test_set_x_roig.shape) #(50, 64, 64, 3) 测试集50行的后面那三个维度的矩阵 print(test_set_y_orig.shape) #(1, 50) 测试集标签1行的50个数据 #降低维度改变数组的位置转置 #匹配标签数据集和训练数据集的维度将高维度的转化为低纬度 #转置是为了方便计算把209放到后面和标签一样 #公式将Aa,b,c,d转化为Ab*c*d,a#XX.reshape(X.shape[0],-1).T#XX.reshape() 重塑数组的维度#(A,B)二维数组#X.shape[0] 第一个维度不变#-1在reshape方法中有一个特殊的意义。它表示该维度的大小应当被自动推断以保证总元素数不变。#为了计算-1应该被替代的值numpy会使用以下方法#总元素数 / 已知的其他维度的大小 未知维度的大小#在Am,n,o中原始数组的总元素数是m * n * o。已知的其他维度的大小是m。所以-1会被计算为(m * n * o) / m n * o。#因此形状为(m, n, o)的三维数组会被重新形状为(m, n*o)的二维数组。#.T 二维数组前后交换 # #测试 # anp.random.rand(5,2,3)#创建[5,2,3]维度的数组用随机数填满 # print(a.shape) #(5, 2, 3) # print((a.reshape(a.shape[0],-1).T).shape) #[6,5]#print(train_set_x_orig.shape) #(209, 64, 64, 3) train_set_x_flattentrain_set_x_orig.reshape(train_set_x_orig.shape[0],-1).T #(12288, 209) # print(train_set_x_flatten.shape)# print(test_set_x_roig.shape)#(50, 64, 64, 3) test_set_x_flattentest_set_x_roig.reshape(test_set_x_roig.shape[0],-1).T #(12288, 50) # print(test_set_x_flatten.shape)#将数据集中化和标准化因为都是图片数据所以可以除以255,将每个数据控制到[0,1]之间 train_set_xtrain_set_x_flatten/255 # print(train_set_x.shape)#数据的维度还是没变(12288, 209) test_set_xtest_set_x_flatten/255#数据处理的部分完成了接下来就是构建神经网络#我们要处理的是二分类问题而“逻辑回归”是处理二分问题的一个算法#逻辑回归实际上是找到一个决策边界然后根据样本点相对于这个边界的位置来分类对于线性逻辑回归这个决策边界是一条直线在二维空间中或一个超平面在更高的维度中这取决于特征的数量。#逻辑回归函数线性回归函数sigmoid函数所以我们需要两个函数#1.线性回归函数Z z^(i) w.T ∙ x^(i)b# x^(i)第i个样本的特征向量# w:权重向量表示当前x^(i)的权重比权重用于决定决策边界怎么画# w.T是w的转置我们为了计算w与x的“点乘”要求w的行向量 x的列向量# 如果你的 w 向量本来就是一个行向量并且它的长度列数与 x 向量的长度行数相同不需要再进行转置但是权重向量和特征向量通常都被定义为列向量这是一种约束。#b: 这是偏置项它是一个常数#z^(i):第i个样本的线性输出。输入一个x^(i)在当前函数中得到一个zi#2.sigmoid函数:a1/1e^(-Z) //其中的Z是线性回归函数#是一种激活函数#输出范围[0,1]#拟合实际上是指尽量减少误分类的数量总有一些点无法分类而我们需要找到可以尽可能的满足多点的决策边界所以我们需要是最小化逻辑回归的损失函数通常是对数损失函数或交叉熵损失函数#所以我们还需要一个损失函数参数:#La^(i),y^(i) -y^(i)*log(a^(i)) - (1-y^(i))*log(1-a^(i))#最后我们需要一个对于所有数据的损失求和的函数假设所有数据一共有m个# J1/m * m∑i1* La^(i),y^(i)#构建sigmoid函数 def sigmoid(z):a1/(1np.exp(-z))return a#初始化函数 #主要用于构建w和b之前看到的方法是创建一个dim1维度的0向量# wnp.zeros(shape(dim,1))#但是这样也许会导致一个“对称性”问题#当你这样初始化权重并使用它们在神经网络中时每一层的所有神经元都会有相同的输出。#因此当你进行反向传播时所有神经元都会收到相同的梯度。这将导致所有的权重都更新为相同的值。无论网络有多少神经元它们都会表现得像一个神经元这极大地限制了网络的容量和表达能力。def initialize_zeros(dim):#dim:传入的数据集的第一个向量坐标X.shape[0]#wnp.zeros(shape(dim,1))w0.01*np.random.rand(dim,1)#乘以0.01是为了确保初始化的权重值很小。b0#使用断言来检测是正确assert(w.shape(dim,1))assert(isinstance(b,float) or isinstance(b,int))return (w,b)#构建逻辑回归的前向传播和后向传播#神经网络或者深度学习模型单次的训练过程有四个阶段#1.前向传播给当前数据x^(i)根据算法当前我们用的是sigmoid函数输出一个结果[sigmoid的范围是[0,1]]#2.计算机损失得到前向传播的数据预测以后我们会评估“预测与我们给定的标签y^(i)”之间的差异。这个差异通常称为“损失”或“误差”#3.后向传播基于前面计算的损失模型会计算每个参数的梯度以知道如何更好地更新参数来提高预测。这个步骤就是告诉模型“为了减少预测误差你应该这样调整你的参数w和b。”#4.更新参数: 在知道了如何更新参数之后实际更新参数。#构建实现上述功能的函数渐变函数 def propagate(w,b,X,Y):#传入的参数# w:权重向量维度为[X.shape[0],1]#每一个元素的值随机 参见初始化函数#w的第一个维度应该等于X.shape[0]为什么因为w.T也就是[1,X.shape[0]]要X进行点乘 参见线性回归函数# b偏差一个常数# X输入的矩阵当前为 (12288, 209)# Y标签矩阵 当前为1,209#返回的参数#cost:当前一轮训练完成后计算得到的损失值的平均,单个的点相较于那条线的成本的总和的平均#dw:后向传播以后w需要改变多少#db:后向传播以后b需要改变多少mX.shape[1] #X的第二个参数也就是样本的总个数#前向传播:也就是执行一次逻辑回归和损失计算也就是执行那三个函数#Zw.T*Xb #线性函数Asigmoid(np.dot(w.T,X)b) #sigmoid函数将线性函数集成了#此时这里A是一个矩阵里面的内容是模型的预测值#使用向量化以后的组合 cost(-1/m)*np.sum(Y*np.log(A) (1-Y)*(np.log(1-A)))#注意因为计算机的时候参与了Y矩阵所以这个时候cost里面有一个下标为1,对于Y1,209来说这个1是确保Y是一个矩阵但是对于cost这个1是无用的我们需要移除costnp.squeeze(cost)#反向传播:计算w和b需要改变多少#为了计算w和b我们需要使用梯度下降算法它的公式是# w w - 学习率 * 损失函数对于w的导数dzA-Ydw (1/m) * np.dot(X,dz.T)db (1/m) * np.sum(dz)#确保数据是否正确assert(dw.shape w.shape)assert(db.dtype float)#断言会失败导致程序抛出一个 AssertionError 异常。assert(cost.shape ())#创建一个字典把dw和db保存起来。grads{dw:dw,db:db}return (grads,cost)#通过最最小化成本函数J来学习w和b def optimize (w,b,X,Y,num_itertions,learning_rate,print_cost False):# 此函数通过运行梯度下降算法来优化w和b# 参数# w - 权重大小不等的数组num_px * num_px * 31# b - 偏差一个标量# X - 维度为num_px * num_px * 3训练数据的数量的数组。# Y - 真正的“标签”矢量如果非猫则为0如果是猫则为1矩阵维度为(1,训练数据的数量)# num_iterations - 优化循环的迭代次数# learning_rate - 梯度下降更新规则的学习率,就是那个阿尔法# print_cost - 每100步打印一次损失值# 返回# params - 包含权重w和偏差b的字典# grads - 包含权重和偏差相对于成本函数的梯度的字典# 成本 - 优化期间计算的所有成本列表将用于绘制学习曲线。# 提示# 我们需要写下两个步骤并遍历它们# 1计算当前参数的成本和梯度使用propagate。# 2使用w和b的梯度下降法则更新参数。costs[]for i in range (num_itertions):grads, cost propagate(w,b,X,Y)dw grads[dw]db grads[db]#公式w w-learning_rate *dwb b-learning_rate *db#记录成本if i %100 0:costs.append(cost)#打印成本数据if (print_cost) and (i % 100 0):print(迭代的次数: %i 误差值 %f % (i,cost))#创建字典保存w和bparams{w:w,b:b}grads{dw:dw,db:db}return (params,grads,costs)# print(测试optimize) # #([[1],[2]])一维的数组有两个元素[1]和[2] # w,b,X,Ynp.array([[1],[2]]), 2 , np.array([[1,2],[3,4]]), np.array([[1,0]]) # params,grads,costsoptimize(w,b,X,Y,num_itertions100,learning_rate 0.009,print_cost False) # print (w str(params[w])) # print (b str(params[b])) # print (dw str(grads[dw])) # print (db str(grads[db]))def predict(w,b,X):#使用学习逻辑回归参数logisticw,b预测标签是0还是1,# 参数# w - 权重大小不等的数组num_px * num_px * 31# b - 偏差一个标量# X - 维度为num_px * num_px * 3训练数据的数量的数组。# 返回# Y_prediction - 包含X中所有图片的所有预测【0 | 1】的一个numpy数组向量mX.shape[1] #图片的数量Y_prediction np.zeros((1,m)) #创建都是0的矩阵1行m列ww.reshape(X.shape[0],1) #将w转为一个图片参数的累乘维度为1#预测猫在图片中出现的概率Asigmoid(np.dot(w.T,X)b)for i in range(A.shape[1]):#将概率a[0,1]转化为实际预测的p[0.i]Y_prediction[0,i] 1 if A[0,i] 0.5 else 0#使用断言assert(Y_prediction.shape(1,m))return Y_prediction # def model(X_train,Y_train,X_test,Y_test, num_iterations2000,learning_rate 0.005, print_costFalse):# #参数 # # X_train -numpy的数组维度为num_px*num_px*3,m_train的训练集 # # Y_train -numpy的数组维度为1,m_train(标签)矢量的训练集合# # X_test -numpy的数组维度为num_px*num_px*3,m_test的测试集 # # Y_test -numpy的数组维度为1,m_test(标签)矢量的测试集合# # num_iterations - 用于优化参数的迭代次数 # # learning_rate --学习率 # # print_cost - 设置为true以每100次迭代打印成本# #返回 # #d -包含模型信息的字典# w,binitialize_zeros(X_train.shape[0]) #初始化w和b,根据训练集合的第一个参数那一堆东西# parameters,grads,costsoptimize(w,b,X_train,Y_train,num_iterations,learning_rate,print_cost)# #从字典“参数”中检索参数w和b # w,b parameters[w],parameters[b]# #预测测试/训练集的例子# Y_prediction_test predict(w,b,X_test) # Y_prediction_trainpredict(w,b,X_train)# #打印 # #用于计算数据的平均值np.mean() # print(训练集的准确度,format(100-np.mean(np.abs(Y_prediction_train-Y_train))*100),%) # print(测试集的准确度,format(100-np.mean(np.abs(Y_prediction_test-Y_test))*100),%)# d { # costs : costs, # Y_prediction_test : Y_prediction_test, # Y_prediciton_train : Y_prediction_train, # w : w, # b : b, # learning_rate : learning_rate, # num_iterations : num_iterations } # return d# print(测试model) # d1model(train_set_x,train_set_y_orig,test_set_x,test_set_y_orig,num_iterations 2000,learning_rate 0.01,print_costTrue) # d2model(train_set_x,train_set_y_orig,test_set_x,test_set_y_orig,num_iterations 2000,learning_rate 0.001,print_costTrue) # d3model(train_set_x,train_set_y_orig,test_set_x,test_set_y_orig,num_iterations 2000,learning_rate 0.0001,print_costTrue)# #绘图 # costs1np.squeeze(d1[costs]) # plt.plot(costs1) # costs2np.squeeze(d2[costs]) # plt.plot(costs2) # costs3np.squeeze(d3[costs]) # plt.plot(costs3)# plt.ylabel(cost) # plt.xlabel((iterations (per hundreds))) # plt.title(Learning rate str(d1[learning_rate])str(d2[learning_rate])str(d3[learning_rate])) # plt.show()def model(X_train , Y_train , X_test , Y_test , num_iterations 2000 , learning_rate 0.5 , print_cost False):w , b initialize_zeros(X_train.shape[0])parameters , grads , costs optimize(w , b , X_train , Y_train,num_iterations , learning_rate , print_cost)#从字典“参数”中检索参数w和bw , b parameters[w] , parameters[b]#预测测试/训练集的例子Y_prediction_test predict(w , b, X_test)Y_prediction_train predict(w , b, X_train)#打印训练后的准确性print(训练集准确性 , format(100 - np.mean(np.abs(Y_prediction_train - Y_train)) * 100) ,%)print(测试集准确性 , format(100 - np.mean(np.abs(Y_prediction_test - Y_test)) * 100) ,%)d {costs : costs,Y_prediction_test : Y_prediction_test,Y_prediciton_train : Y_prediction_train,w : w,b : b,learning_rate : learning_rate,num_iterations : num_iterations }return dprint(测试model) #这里加载的是真实的数据请参见上面的代码部分。 d model(train_set_x, train_set_y_orig, test_set_x, test_set_y_orig, num_iterations 2000, learning_rate 0.005, print_cost True) #绘制图 costs np.squeeze(d[costs]) plt.plot(costs) plt.ylabel(cost) plt.xlabel(iterations (per hundreds)) plt.title(Learning rate str(d[learning_rate])) plt.show()最后我们得到了这样的结果和图片 6.5 再玩一下好的 让我们最后修改一下学习率看看会有什么样的变化 如果你也想玩替换最后的打印语句即可: print(测试model) d1model(train_set_x,train_set_y_orig,test_set_x,test_set_y_orig,num_iterations 2000,learning_rate 0.01,print_costTrue) d2model(train_set_x,train_set_y_orig,test_set_x,test_set_y_orig,num_iterations 2000,learning_rate 0.001,print_costTrue) d3model(train_set_x,train_set_y_orig,test_set_x,test_set_y_orig,num_iterations 2000,learning_rate 0.0001,print_costTrue)#绘图 costs1np.squeeze(d1[costs]) plt.plot(costs1) costs2np.squeeze(d2[costs]) plt.plot(costs2) costs3np.squeeze(d3[costs]) plt.plot(costs3)plt.ylabel(cost) plt.xlabel((iterations (per hundreds))) plt.title(Learning rate1 str(d1[learning_rate])\nLearning rate2 str(d2[learning_rate])\nLearning rate2 str(d2[learning_rate])) plt.show()得到的结果是这样滴 为什么呢 学习率会有影响 我知道为什么会这样呢 你猜 写在后面的话 这应该是我注册CSDN以来写的最畅快的一片博客。 对于标题《打开深度学习的锁》其实有很多自负我甚至连那扇门都没有看到…但我依然感觉的到我解开了一些东西这种感觉很舒服也很自豪。 好似小学课堂上我第一次解开方程组老师奖励的那块糖。那颗糖打开了我喜欢数学的门而这道题打开我对于深度学习的那把锁以此畅快。 很久没有写博客了。为什么不写呢原因很多没时间、没心气、没东西. 写博客曾经是我学习的一种的方式本人比较笨也比较懒对于一个知识点往往需要很长的周期才可以掌握。但我依然希望沉淀一点东西然后写下来。保留这份难得沉下心这个为了一个目标的渴望与完成时的激动。 在未来的某个时段作为引子以供以后的自己检索回忆。 也可看自己是增是减。 我曾经写过很多没用的东西但就是这些东西记录了当年那个小小的自己自顾自的向前走时不时跌到、颓废、崩溃、抑郁、焦虑、然后起身、振作、自我调节、继续行走。如今回到看那个少年也走出了一条窄窄的路。 那个孩子仍然在以自己的方式——迎接自己渴望的欢呼承受自己唾弃的鄙夷走下去。 郝佳顺 2023年9月9日 于韩国庆北大学
http://www.w-s-a.com/news/399084/

相关文章:

  • 南昌网站建设模板合作凡客app哪去了
  • 有免费做网站的吗建设互联网站
  • 北京市保障房建设投资中心网站淄博哪个网站做房屋出赁好
  • 如何做网站的优化网站开发怎么收费
  • 网站的关键词怎么选择2345实用查询
  • 免费的制作网站做图剪片文案网站app接单
  • 中国有多少网站有多少域名上海网站建设网页制作邢台
  • 网站 数据报表如何做室内设计联盟官方网站入口
  • 怎样建设网站论文合肥做网站的软件公司
  • 收款后自动发货的网站是怎么做的怎么看网站后台网页尺寸
  • 谷歌seo引擎优化宁波seo关键词
  • 外贸网站建设需要注意什么seo课程
  • 做信息图网站网站建设的软件介绍
  • 网站开发语言数据库有几种魏县审批建设的网站
  • 北京公司网站建设推荐海口建设
  • 不懂编程如何做网站婚礼网站模板
  • 像京东一样的网站wordpress入门视频教程7 - 如何在文章里加入视频和音乐
  • 惠州网站建设排名wordpress3万篇文章优化
  • 创建网站的三种方法北京建王园林工程有限公司
  • jsp网站建设模板下载十大免费excel网站
  • 网络公司网站图片网站建立好了自己怎么做优化
  • 云主机是不是可以搭建无数个网站百度快速seo优化
  • 房地产怎么做网站推广建立音乐网站
  • 川畅科技联系 网站设计网站开发的教学视频
  • 为什么学网站开发凡科登陆
  • 设计师常备设计网站大全中山精品网站建设信息
  • 杭州建设工程网seo服务是什么
  • 兼职做问卷调查的网站wordpress mysql设置
  • 怎么在百度上能搜到自己的网站山西seo谷歌关键词优化工具
  • 网站搭建免费模板飞鱼crm下载