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

建设部网站施工员查询外贸推广的几种方式以及效果排行

建设部网站施工员查询,外贸推广的几种方式以及效果排行,合肥建网站公司,河北邯郸网站制作这篇博文不涉及理论知识#xff0c;主要通过一个完整的深度学习模型训练流程#xff0c;直观地了解深度学习图像分类任务。有关理论的部分#xff0c;之前几篇博文已经涉及基础部分#xff0c;之后也会对一些理论进行补充。 本文将结合代码#xff0c;主要介绍三部分内容…这篇博文不涉及理论知识主要通过一个完整的深度学习模型训练流程直观地了解深度学习图像分类任务。有关理论的部分之前几篇博文已经涉及基础部分之后也会对一些理论进行补充。 本文将结合代码主要介绍三部分内容 1. 数据集划分 2. 模型训练 3. 模型评估 本文集成了深度学习图像处理从数据集划分到模型训练最后到模型评估的一个完整框架。旨在方便从事相关学术研究的伙伴进行实验对比。 1. 数据集划分 1.1 数据集文件结构 数据集结构如上图所示共分三级目录。根目录dataset一级子目录animal-5二级子目录5种动物的类别。每个动物类别的文件夹中保存对应类别的图片。 1.2 数据集划分 数据集划分的步骤 1读取数据集中所有图片的路径。 2随机选取图片将数据集按照41的比例划分为训练集和测试集。 3标签映射将数据集标签映射到json文件中保存。 1.3 代码 代码文件名称split_data.py 完整代码 import os import random import json import argparsedef split_data(dataset_root, txt_save_root, ratio):assert 0 ratio 1, ratio must be between 0 and 1# 创建保存路径文件夹os.makedirs(txt_save_root, exist_okTrue)# 获取所有文件路径all_files []for path, _, files in os.walk(dataset_root):for file in files:all_files.append(os.path.join(path, file))# 将文件路径保存到 dataset.txtwith open(f{txt_save_root}/dataset.txt, w) as f:for file_path in all_files:f.write(file_path \n)print(f数据集路径保存成功到{txt_save_root}/dataset.txt)# 随机分割为训练集和测试集random.shuffle(all_files)split_index int(ratio * len(all_files))train_files all_files[:split_index]test_files all_files[split_index:]# 将训练集和测试集的路径分别保存with open(f{txt_save_root}/train.txt, w) as f:for file_path in train_files:f.write(file_path \n)print(f训练集路径保存成功到{txt_save_root}/train.txt)with open(f{txt_save_root}/test.txt, w) as f:for file_path in test_files:f.write(file_path \n)print(f测试集路径保存成功到{txt_save_root}/test.txt)def get_paths_and_labels(filename):paths_and_labels []with open(filename, r) as file:for line in file:path line.strip() # 移除行尾的换行符label get_label_from_path(path)paths_and_labels.append((path, label))return paths_and_labelsdef get_label_from_path(image_path):parts image_path.split(\\)label parts[-2] if len(parts) 1 else Nonereturn labeldef create_and_save_label_mapping(file_paths_and_labels, json_file):unique_labels sorted(set(label for _, label in file_paths_and_labels))label_to_index {label: index for index, label in enumerate(unique_labels)}with open(json_file, w) as file:json.dump(label_to_index, file)if __name__ __main__:# 创建 ArgumentParser 对象parser argparse.ArgumentParser(descriptionProcess some paths.)# 添加参数parser.add_argument(--dataset_root, defaultdataset/animal-5,typestr, help数据集根路径)parser.add_argument(--txt_save_root, defaultfile/animal-5,typestr, helptxt文件保存路径)parser.add_argument(--ratio, default0.8, typefloat, help训练集的比例)# 解析参数args parser.parse_args()dataset_root args.dataset_roottxt_save_root args.txt_save_rootratio args.ratio# 划分数据集split_data(dataset_root, txt_save_root, ratio)# 获取数据集标签file_paths_and_labels get_paths_and_labels(f{txt_save_root}/train.txt)print(f成功获取数据集标签)# 记录数据集标签映射create_and_save_label_mapping(file_paths_and_labels, f{txt_save_root}/classes.json)print(f已保存数据集标签映射到{txt_save_root}/classes.json) 1.4 代码使用方法 parser.add_argument(--dataset_root, defaultdataset/animal-5,typestr, help数据集根路径) parser.add_argument(--txt_save_root, defaultfile/animal-5,typestr, helptxt文件保存路径) parser.add_argument(--ratio, default0.8, typefloat, help训练集的比例)运行代码时只需要更改上述参数中的 default 部分。--dataset_root为数据集根路径。--txt_save_root为txt文件保存路径。--ratio为训练集占数据集的比例大于0小于1。 上述代码运行成功后结果如下 其中dataset.txt保存了数据集所有图片的路径train.txt保存了所有训练集图片路径test.txt保存了所有测试集图片路径classes.json保存了该数据集标签的映射。 上述四个文件部分内容展示如下 2. 模型训练 2.1 模型训练步骤 1环境准备和参数解析 导入必要的库和模块如torch, torchvision, sklearn.model_selection等。定义一个解析命令行参数的argparse.ArgumentParser实例用于接收从命令行传入的参数如训练集路径、模型保存路径、批大小、学习率、是否使用预训练模型等。 2数据准备 使用给定的文件路径和JSON文件加载训练图像的路径和对应的标签映射。将数据集划分为训练集和验证集。定义数据预处理步骤包括图像的尺寸调整、随机裁剪、归一化等。创建CustomDataset类的实例用于加载和转换图像数据。使用DataLoader对训练集和验证集进行批处理准备输入模型的数据。 3模型准备 根据命令行参数选择不同的模型架构如ResNet18、ResNet50、MobileNetV2等并根据是否使用预训练模型进行相应配置。将模型移至适当的设备CPU或GPU。 4训练与验证 定义损失函数交叉熵损失和优化器Adam优化器。对模型进行多个周期的训练和验证 训练阶段模型在训练模式下运行。对每个批次的数据执行前向传播、计算损失、执行反向传播并更新模型参数。验证阶段模型在评估模式下运行计算验证集上的损失和准确率以评估模型的性能。在每个周期结束时如果验证准确率有所提高则保存当前最佳模型。为了便于模型的恢复和进一步训练每隔一定周期保存模型的检查点。 5结果保存 将训练过程中得到的最佳模型保存到指定路径。可选地保存训练过程中的一些检查点以便未来可以从特定的周期恢复训练。 2.2 代码 以下是一个动物图像分类的训练脚本使用PyTorch框架。它包含了从数据预处理到模型训练、验证以及保存模型的完整流程。 文件名train.py import torch import torch.nn as nn import torch.optim as optim from torch.utils.data import DataLoader, Dataset from torchvision import transforms, models from sklearn.model_selection import train_test_split import os from split_data import get_label_from_path import json from tqdm import tqdm from PIL import Image import argparsedef resize_and_pad(image, target_height224, target_width224):# 将PIL Image对象直接用于获取其尺寸original_width, original_height image.size# 计算宽度和高度的缩放比例scale min(target_width / original_width, target_height / original_height)# 应用等比例缩放new_width, new_height int(original_width * scale), int(original_height * scale)resized_image image.resize((new_width, new_height), Image.Resampling.LANCZOS)# 创建填充用的背景图像if image.mode L: # 灰度图mode Lelif image.mode in [RGB, RGBA]: # RGB或RGBA彩色图mode image.modeelse:raise ValueError(Unsupported image mode.)# 创建一个新的空白图片用于填充padded_image Image.new(mode, (target_width, target_height))# 计算填充位置start_x (target_width - new_width) // 2start_y (target_height - new_height) // 2# 将缩放后的图像粘贴到新的背景图中padded_image.paste(resized_image, (start_x, start_y))return padded_imageclass CustomDataset(Dataset):def __init__(self, file_paths, label_mapping, transformNone):self.file_paths file_pathsself.label_mapping label_mappingself.transform transformdef __len__(self):return len(self.file_paths) # 返回数据集中的样本数量def __getitem__(self, idx):image_path self.file_paths[idx]image Image.open(image_path).convert(RGB)image resize_and_pad(image, 224, 224)label_str get_label_from_path(image_path)label self.label_mapping[label_str] # 使用映射转换标签if self.transform:to_tensor transforms.ToTensor()image to_tensor(image)return image, torch.tensor(label), image_pathdef train(model, train_loader, criterion, optimizer, device):model.train()running_loss 0.0correct 0total 0for images, labels, image_path in tqdm(train_loader, descTraining):images images.float() # 将输入数据转换为FloatTensorimages, labels images.to(device), labels.to(device)optimizer.zero_grad()outputs model(images)loss criterion(outputs, labels)loss.backward()optimizer.step()running_loss loss.item()_, predicted torch.max(outputs.data, 1)total labels.size(0)correct (predicted labels).sum().item()accuracy 100 * correct / totalreturn running_loss / len(train_loader), accuracydef validate(model, val_loader, criterion, device):model.eval()running_loss 0.0correct 0total 0with torch.no_grad():for images, labels, image_path in tqdm(val_loader, descValidation):images images.float() # 将输入数据转换为FloatTensorimages, labels images.to(device), labels.to(device)outputs model(images)loss criterion(outputs, labels)running_loss loss.item()_, predicted torch.max(outputs.data, 1)total labels.size(0)correct (predicted labels).sum().item()accuracy 100 * correct / totalreturn running_loss / len(val_loader), accuracydef main(args):# 解析参数train_path args.train_pathjson_path args.json_pathsave_path args.save_pathlr args.lrbatch_size args.batch_sizepretrained args.pretrainedmodel_name args.model# 创建保存路径os.makedirs(save_path, exist_okTrue)# 读取数据with open(train_path, r) as file:file_paths [line.strip() for line in file.readlines()]# 加载标签映射with open(json_path, r) as file:label_mapping json.load(file)img_size {s: [224, 224], # train_size, val_sizem: [384, 480],l: [384, 480]}num_model s# 划分训练集和验证集train_paths, val_paths train_test_split(file_paths, test_size0.1)# 数据预处理transform {train: transforms.Compose([transforms.RandomResizedCrop(img_size[num_model][0]),transforms.RandomHorizontalFlip(),transforms.ToTensor(),transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])]),val: transforms.Compose([transforms.Resize(img_size[num_model][1]),transforms.ToTensor(),transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])])}# 创建数据集和数据加载器train_dataset CustomDataset(train_paths, label_mapping, transformtransform[train])val_dataset CustomDataset(val_paths, label_mapping, transformtransform[val])train_loader DataLoader(train_dataset, batch_sizebatch_size, shuffleTrue)val_loader DataLoader(val_dataset, batch_sizebatch_size, shuffleFalse)# 定义模型device torch.device(cuda if torch.cuda.is_available() else cpu)if model_name resnet50:model models.resnet50(pretrainedpretrained) # resnet50elif model_name resnet18:model models.resnet18(pretrainedpretrained) # resnet18elif model_name resnet34:model models.resnet34(pretrainedpretrained) # resnet34elif model_name resnet101:model models.resnet101(pretrainedpretrained) # resnet101elif model_name mobilenetv2:model models.mobilenet_v2(pretrainedpretrained) # mobilenetv2elif model_name convnext:model models.convnext_base(pretrainedpretrained) # convnext_baseelif model_name efficientnetv2:model models.efficientnet_v2_s(pretrainedpretrained) # efficientnet_v2_smodel model.to(device)# 定义损失函数和优化器criterion nn.CrossEntropyLoss()optimizer optim.Adam(model.parameters(), lrlr)# 训练和验证epochs args.epochsbest_val_accuracy 0.0 # 用于跟踪最高验证准确率for epoch in range(epochs):train_loss, train_accuracy train(model, train_loader, criterion, optimizer, device)val_loss, val_accuracy validate(model, val_loader, criterion, device)print()print(fEpoch {epoch 1}/{epochs} - fTrain Loss: {train_loss:.4f}, Train Accuracy: {train_accuracy:.2f}% - fVal Loss: {val_loss:.4f}, Val Accuracy: {val_accuracy:.2f}%)# 如果当前验证准确率高于之前的最高准确率则保存模型if val_accuracy best_val_accuracy:best_val_accuracy val_accuracytorch.save(model.state_dict(), f{save_path}/best_model.pt)print(f\nValidation accuracy improved to {val_accuracy:.2f}%. Saving model to {save_path}/best_model.pt)if (epoch 1) % 10 0 :checkpoint_path f{save_path}/model_epoch_{epoch 1}.pttorch.save(model.state_dict(), checkpoint_path)print(fSaved model checkpoint to {checkpoint_path} at epoch {epoch 1}.)if __name__ __main__:# 创建 ArgumentParser 对象parser argparse.ArgumentParser(descriptionProcess some paths.)# 添加参数parser.add_argument(--train_path, defaultfile/animal-5/train.txt,typestr, help保存训练集路径的txt文件路径)parser.add_argument(--json_path, defaultfile/animal-5/classes.json,typestr, help映射标签的json文件路径)parser.add_argument(--save_path, defaultresult/resnet18,typestr, help模型保存路径)parser.add_argument(--batch_size, default32, typeint)parser.add_argument(--lr, default2e-4, typefloat)parser.add_argument(--pretrained, defaultFalse, typebool, help是否使用预训练模型)parser.add_argument(--ratio, default0.1, typefloat, help划分验证集的数据比例)parser.add_argument(--epochs, default100, typeint, help训练总次数)parser.add_argument(--model, defaultresnet18, typestr,helpresnet18, resnet50, resnet101, )args parser.parse_args()main(args) 2.3 代码使用方法 根据实际需要和代码提示对以下参数的default进行更改即可。 1参数列表 --train_path指定保存训练集图片路径的文本文件的路径。默认值为file/animal-5/train.txt。这个文件应该包含所有训练图像的路径每个路径占一行。 --json_path指定包含标签和对应类别映射的JSON文件的路径。默认值为file/animal-5/classes.json。这个文件用于将图像的标签例如类别名称映射为模型训练时使用的整数索引。 --save_path指定训练完成的模型保存位置的路径。默认值为result/resnet18。如果训练过程中的验证准确率超过了之前的最高纪录最佳模型将被保存到这个位置。 --batch_size训练和验证过程中的批处理大小。默认值为32。这决定了每次前向和反向传播过程中将处理多少图像。 --lr学习率优化器使用的学习率。默认值为0.0002。学习率决定了模型参数在每次迭代中更新的幅度。 --pretrained是否使用预训练的模型作为起点进行训练。默认为False。如果设置为True模型将使用在大型数据集如ImageNet上预先训练得到的权重这通常可以帮助改进模型的性能。 --ratio用于从训练数据中划分验证集的数据比例。默认值为0.1即10%的训练数据将被用作验证集。 --epochs总训练周期数。默认值为100。这决定了整个训练集将被遍历多少次。 --model选择使用的模型架构。默认为resnet18。该参数允许用户根据需要选择不同的模型架构例如resnet50, resnet101等。 2使用命令 基于默认参数运行脚本的示例命令如下 python train.py 如果需要自定义参数可以在命令后添加相应的选项如下所示python train.py --train_path mypath/train.txt --json_path mypath/classes.json --save_path myresult --batch_size 64 --lr 0.001 --pretrained True --epochs 50 --model resnet50训练过程效果图 3. 模型评估 3.1 模型评估步骤  1参数解析 通过argparse库脚本首先定义了一系列命令行参数允许用户指定测试数据集路径、类别标签的JSON文件路径、模型保存路径、结果输出路径、是否使用预训练模型以及模型的类型。 2环境设置 确定模型运行的设备CPU或GPU并设置好确保评估过程能够利用硬件加速。 3模型加载 根据用户指定的模型类型和是否使用预训练权重加载相应的模型架构。支持多种模型如ResNet18、ResNet50等。遍历模型保存路径下所有指定的模型检查点文件对每个模型进行加载和评估。 4测试数据准备 读取测试集图像路径列表和标签映射文件。定义图像预处理流程包括尺寸调整、归一化等。使用CustomDataset类从train模块导入创建测试数据集然后使用DataLoader准备用于批量评估的测试数据。 5模型评估 对每个加载的模型遍历测试数据集预测图像标签并收集所有预测结果和真实标签。计算混淆矩阵以及其他关键性能指标如准确率、精确度、召回率和F1得分。 6结果输出 打印混淆矩阵和评估指标。将混淆矩阵和评估指标保存为CSV文件方便后续查看和分析。 3.2 代码 import osimport torch from torch.utils.data import DataLoader, Dataset import json from sklearn.metrics import confusion_matrix, accuracy_score, precision_score, recall_score, f1_score import pandas as pd from torchvision import transforms, models from train import CustomDataset from tqdm import tqdm import argparsedef evaluate(model, test_loader, device, label_mapping):model.eval()all_preds []all_labels []with torch.no_grad():for images, labels, img_paths in tqdm(test_loader, descTest):images images.float() # 将输入数据转换为FloatTensorimages images.to(device)outputs model(images)_, predicted torch.max(outputs.data, 1)all_preds.extend(predicted.cpu().numpy())all_labels.extend(labels.cpu().numpy())# 计算混淆矩阵cm confusion_matrix(all_labels, all_preds)return cm, all_labels, all_predsdef main(args):# 解析参数test_path args.test_pathjson_path args.json_pathmodel_path args.model_pathpretrained args.pretrainedmodel_name args.modelresult_path args.result_pathos.makedirs(result_path, exist_okTrue)# 加载模型if model_name resnet50:model models.resnet50(pretrainedpretrained) # resnet50elif model_name resnet18:model models.resnet18(pretrainedpretrained) # resnet18elif model_name resnet34:model models.resnet34(pretrainedpretrained) # resnet34elif model_name resnet101:model models.resnet101(pretrainedpretrained) # resnet101elif model_name mobilenetv2:model models.mobilenet_v2(pretrainedpretrained) # mobilenetv2elif model_name convnext:model models.convnext_base(pretrainedpretrained) # convnext_baseelif model_name efficientnetv2:model models.efficientnet_v2_s(pretrainedpretrained) # efficientnet_v2_spaths_list [best_model.pt,model_epoch_10.pt, model_epoch_20.pt,model_epoch_30.pt, model_epoch_40.pt,model_epoch_50.pt, model_epoch_60.pt,model_epoch_70.pt, model_epoch_80.pt,model_epoch_90.pt, model_epoch_100.pt,]for _ in paths_list:path f{model_path}/{_}# 加载保存的权重model.load_state_dict(torch.load(path))device torch.device(cuda if torch.cuda.is_available() else cpu)model model.to(device)# 加载测试集with open(test_path, r) as file:test_paths [line.strip() for line in file]# 加载标签映射with open(json_path, r) as file:label_mapping json.load(file)# 设置数据转换transform transforms.Compose([transforms.Resize((224, 224)), # 示例尺寸根据需要调整transforms.ToTensor(),transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])])# 创建测试数据集和数据加载器test_dataset CustomDataset(test_paths, label_mapping, transformtransform)test_loader DataLoader(test_dataset, batch_size1, shuffleFalse)# 设备配置device torch.device(cuda if torch.cuda.is_available() else cpu)model.to(device)# 评估模型conf_matrix, labels, preds evaluate(model, test_loader, device, label_mapping)# 打印混淆矩阵print(f{path}: )print(Confusion Matrix:)print(conf_matrix)# 计算评估指标accuracy accuracy_score(labels, preds)precision precision_score(labels, preds, averagemacro)recall recall_score(labels, preds, averagemacro)f1 f1_score(labels, preds, averagemacro)# 创建包含混淆矩阵的DataFrameconf_matrix_df pd.DataFrame(conf_matrix, columnslabel_mapping.keys(), indexlabel_mapping.keys())conf_matrix_df.index.name Actualconf_matrix_df.columns.name Predicted# 将评估指标添加到混淆矩阵的下方metrics_df pd.DataFrame({Metric: [Accuracy, Precision, Recall, F1 Score],Value: [accuracy, precision, recall, f1]})# 保存混淆矩阵和评估指标到CSV文件combined_df pd.concat([conf_matrix_df, metrics_df], axis0)combined_df.to_csv(f{result_path}/{_}_confusion_matrix.csv, indexTrue)# 打印指标print(metrics_df)if __name__ __main__:# 创建 ArgumentParser 对象parser argparse.ArgumentParser(descriptionProcess some paths.)# 添加参数parser.add_argument(--test_path, defaultfile/animal-5/test.txt,typestr, help保存训练集路径的txt文件路径)parser.add_argument(--json_path, defaultfile/animal-5/classes.json,typestr, help映射标签的json文件路径)parser.add_argument(--model_path, defaultresult/resnet18,typestr, help模型保存路径)parser.add_argument(--result_path, defaultresult/resnet18_csv,typestr, help保存混淆矩阵和评估结果到csv文件的路径)parser.add_argument(--pretrained, defaultFalse, typebool, help是否使用预训练模型)parser.add_argument(--model, defaultresnet18, typestr,helpresnet18, resnet50, resnet101)args parser.parse_args()main(args) 3.3 代码使用方法 1参数详解 script_name.py替换为脚本的文件名。--test_path path_to_test_txt指向一个文本文件的路径该文件包含了测试集图像的路径。每个路径应该占一行。--json_path path_to_classes_json指向一个JSON文件的路径该文件包含了标签到类别的映射。--model_path path_to_saved_models模型保存的文件夹路径。这是训练过程中保存的模型权重。--result_path path_for_output_csv输出结果的文件夹路径。混淆矩阵和性能指标的CSV文件将保存在这里。--pretrained True_or_False指定是否使用预训练的模型权重。应该为True或False。--model model_type指定模型的类型。可以是resnet18, resnet50, resnet101等。 2示例命令 假设你的脚本名为evaluate.py测试数据列表保存在./file/animal-5/test.txt标签映射文件位于./file/animal-5/classes.json训练好的模型保存在./result/resnet18你希望将结果保存到./result/resnet18_csv并且你使用的是预训练的resnet18模型以下是相应的命令 python evaluate.py --test_path ./file/animal-5/test.txt --json_path ./file/animal-5/classes.json --model_path ./result/resnet18 --result_path ./result/resnet18_csv --pretrained True --model resnet18确保替换命令中的路径和参数以匹配你的具体情况。运行此命令后脚本将使用指定的测试数据评估模型并将混淆矩阵及性能指标输出到指定的路径。 控制台输出结果 csv保存结果 4. 总结 我们深入探讨了深度学习在图像分类任务中的应用以动物分类为例进行了实战演练。我们从数据集的准备和预处理开始探讨了如何通过调整图像尺寸和应用数据增强技术来提高模型的泛化能力。接着我们讨论了不同的深度学习模型架构训练代码中集成了如ResNet和MobileNet等模型并介绍了如何使用PyTorch框架来训练这些模型。 我们通过命令行参数灵活地控制训练过程允许用户自定义模型训练的各个方面包括模型的选择、是否使用预训练权重、学习率和批大小等。通过实现自定义的数据加载器我们能够有效地处理图像数据和标签为模型训练和评估提供了强大的支持。 在模型训练部分我们强调了训练过程中的关键环节如损失函数的选择、优化器的配置以及如何根据验证集的表现来保存最佳模型。此外我们还探讨了模型评估的重要性通过计算混淆矩阵和关键性能指标如准确率、精确度、召回率和F1得分来深入了解模型在未见数据上的表现。 在整个系列中我们的目标是提供一个全面的指南帮助读者了解和实现一个完整的图像分类项目。通过详细的代码示例和解释我们希望读者能够不仅理解深度学习模型背后的原理还能够自信地应用这些技术来解决自己感兴趣的问题。 之后我们会陆续更新不同的深度学习图像处理的技术和代码不仅向大家提供便于在实验中使用的代码也尽量提供能落地应用的代码框架。
http://www.pierceye.com/news/622476/

相关文章:

  • 毕节市住房和城乡建设局网站做wordpress总结
  • 桐城市建设局网站wordpress主题美容
  • 海阳市城建设局网站深圳高端设计公司名单
  • 高端网站制作系统网站开发的背景和意义
  • 假电影网站做注册长春seo代理计费
  • 网站代运营公司怎么做vip电影网站
  • 南京网站南京网站设计制作公司提高工作效率
  • 大连网站制作最好的公司萍乡商城网站建设
  • 做网站有2个前提条件_一个是网站班级优化大师app下载学生版
  • 自己做网站广告法wordpress自带评论表情
  • 苏州市城乡和建设局网站首页在线crm系统价格
  • php企业门户网站陕西高速公路建设网站
  • 网站商城系统建设方案h5页面制作网站易企秀
  • 绍兴网站建设方案报价seo外贸网站
  • 物流网站建设重要性建筑公司网址大全
  • 腾讯云注册域名后怎么做网站郑州网站建设大华伟业
  • 哪个小说网站可以做封面中国软件园排名前十
  • 门户网站建设预算表十大软件免费下载安装手机版
  • 河南省安阳市建设银行网站wordpress会员卡
  • 旅游类网站怎么做网站前端设计
  • 涉县网站设计商城网站建设推荐
  • 网站注册了域名然后怎么做网站运维是做什么的
  • 深圳学校网站建设哪家好企业宣传网
  • 静态网站如何添加关键词xp花生壳做网站
  • 南宁霸屏网站开发国际数据公司idc
  • 百色建设网站广西建设监理协会网站
  • 天河营销型网站建设惠东网站设计
  • 网站建设用什么科目qq腾讯官网登录入口
  • 做网站硬件手表网站哪个最好知乎
  • 网站制作教程及流程网站优化常见的优化技术