IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> 深度学习实战—基于Keras的手写数字识别(非常详细、代码开源) -> 正文阅读

[人工智能]深度学习实战—基于Keras的手写数字识别(非常详细、代码开源)

??本来想着多更新一些关于深度学习的文章,但这方面知识专业度很高,如果作者本身都掌握不好,又怎么能写出好文章分享呢?

??距离第一篇关于深度学习的文章:深度学习笔记1——激活函数,已经过去了9个多月,在沉淀了9个月后,这次写出了第二篇关于深度学习的文章,而且出于快速上手代码编写的目的,这次直接进行手写数字识别的实战,且看下文:

一、准备工作

设备\库型号\版本
显卡GTX1650
驱动程序版本457.49
tensorflow-gpu版本2.4.0
keras版本2.4.3
Python版本3.7.3

二、下载MNIST数据集

Keras已经对MNIST数据集做了集成,可以直接通过API下载与使用。

2.1 导入所需的库与模块

from keras.datasets import mnist
import matplotlib.pyplot as plt

2.2 下载数据集

# x_train_original和y_train_original代表训练集的图像与标签, x_test_original与y_test_original代表测试集的图像与标签
(x_train_original, y_train_original), (x_test_original, y_test_original) = mnist.load_data()

下载好的数据集系统会存放在C盘用户下的.keras中的datasets文件夹下:

C:\Users\Lenovo\.keras\datasets

在这里插入图片描述

三、数据集可视化

3.1 单张图像可视化

def mnist_visualize_single(mode, idx):
    if mode == 0:
        plt.imshow(x_train_original[idx], cmap=plt.get_cmap('gray'))
        title = 'label=' + str(y_train_original[idx])
        plt.title(title)
        plt.xticks([])
        plt.yticks([])
        plt.show()
    else:
        plt.imshow(x_test_original[idx], cmap=plt.get_cmap('gray'))
        title = 'label=' + str(y_test_original[idx])
        plt.title(title)
        plt.xticks([])
        plt.yticks([])
        plt.show()

我们调用这个函数

mnist_visualize_single(mode=0, idx=0)

在这里插入图片描述
可以看到,训练数据的第一张图像是5。

3.2 多张图像可视化

def mnist_visualize_multiple(mode, start, end, length, width):
    if mode == 0:
        for i in range(start, end):
            plt.subplot(length, width, 1 + i)
            plt.imshow(x_train_original[i], cmap=plt.get_cmap('gray'))
            title = 'label=' + str(y_train_original[i])
            plt.title(title)
            plt.xticks([])
            plt.yticks([])
        plt.show()
    else:
        for i in range(start, end):
            plt.subplot(length, width, 1 + i)
            plt.imshow(x_test_original[i], cmap=plt.get_cmap('gray'))
            title = 'label=' + str(y_test_original[i])
            plt.title(title)
            plt.xticks([])
            plt.yticks([])
        plt.show()

我们调用这个函数

mnist_visualize_multiple(mode=0, start=0, end=4, length=2, width=2)

在这里插入图片描述
可以看到,训练数据的前四张图像分别是5、0、4、1。

3.3 原始数据量可视化

print('训练集图像的尺寸:', x_train_original.shape)
print('训练集标签的尺寸:', y_train_original.shape)
print('测试集图像的尺寸:', x_test_original.shape)
print('测试集标签的尺寸:', y_test_original.shape)

程序运行结果:

训练集图像的尺寸: (60000, 28, 28)
训练集标签的尺寸: (60000,)
测试集图像的尺寸: (10000, 28, 28)
测试集标签的尺寸: (10000,)

从这里可以知道,MNIST数据集是(28×28)的灰度图像

四、数据预处理

4.1 验证集分配

我们从训练集的60000张图像中,分离出10000张图像用作验证集。

x_val = x_train_original[50000:]
y_val = y_train_original[50000:]
x_train = x_train_original[:50000]
y_train = y_train_original[:50000]
# 打印验证集数据量
print('验证集图像的尺寸:', x_val.shape)
print('验证集标签的尺寸:', y_val.shape)

程序运行结果:

验证集图像的尺寸: (10000, 28, 28)
验证集标签的尺寸: (10000,)

4.2 图像数据预处理

我们需要先将图像转换为四维矩阵用于网络训练,且需要把图像类型从Uint8转化为float32,提高训练精度。

x_train = x_train.reshape(x_train.shape[0], 28, 28, 1).astype('float32')
x_val = x_val.reshape(x_val.shape[0], 28, 28, 1).astype('float32')
x_test = x_test_original.reshape(x_test_original.shape[0], 28, 28, 1).astype('float32')

原始图像数据的像素灰度值范围是0-255,为了提高模型的训练精度,通常将数值归一化至0-1。

x_train = x_train / 255
x_val = x_val / 255
x_test = x_test / 255

我们打印一下数据集传入网络的尺寸:

print('训练集传入网络的图像尺寸:', x_train.shape)
print('验证集传入网络的图像尺寸:', x_val.shape)
print('测试集传入网络的图像尺寸:', x_test.shape)

打印结果为:

训练集传入网络的图像尺寸: (50000, 28, 28, 1)
验证集传入网络的图像尺寸: (10000, 28, 28, 1)
测试集传入网络的图像尺寸: (10000, 28, 28, 1)

五、构建网络

5.1 导入所需的库与模块

import numpy as np
import pandas as pd
from sklearn.metrics import confusion_matrix
import seaborn as sns
from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D, Flatten, Dense
from keras.utils import np_utils
from keras.utils.vis_utils import plot_model

5.2 定义网络模型

我们使用CNN模型做手写数字的分类,当然也可以使用感知机。

模型的构建采用序贯模型结构,网络由卷积层-池化层-卷积层-池化层-平铺层-全连接层-全连接层组成。最后一层的全连接层采用softmax激活函数做10分类。

def CNN_model():

    model = Sequential()
    model.add(Conv2D(filters=16, kernel_size=(5, 5), activation='relu', input_shape=(28, 28, 1)))
    model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))
    model.add(Conv2D(filters=32, kernel_size=(5, 5), activation='relu', input_shape=(28, 28, 1)))
    model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))
    model.add(Flatten())
    model.add(Dense(100, activation='relu'))
    model.add(Dense(10, activation='softmax'))

    print(model.summary())
    return model
    
model = CNN_model()

5.3 网络模型参数可视化

我们使用print(model.summary())得到神经网路的每一层参数。

print(model.summary())

输出结果为:

Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d (Conv2D)              (None, 24, 24, 16)        416       
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 12, 12, 16)        0         
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 8, 8, 32)          12832     
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 4, 4, 32)          0         
_________________________________________________________________
flatten (Flatten)            (None, 512)               0         
_________________________________________________________________
dense (Dense)                (None, 100)               51300     
_________________________________________________________________
dense_1 (Dense)              (None, 10)                1010      
=================================================================
Total params: 65,558
Trainable params: 65,558
Non-trainable params: 0
_________________________________________________________________

5.4 网络结构可视化

为了更直观的展示网络的结构,我们可以通过图的方式了解网络各层之间的关系:

plot_model(model, to_file='CNN_model.png', show_shapes=True, show_layer_names=True, rankdir='TB')
plt.figure(figsize=(10, 10))
img = plt.imread('CNN_model.png')
plt.imshow(img)
plt.axis('off')
plt.show()

在这里插入图片描述
网络结构图可以更加直观的看出网络各层关系以及张量流的传递路径,此外每个网络层的输入输出尺寸都能很好的体现。

六、编译训练网络

6.1 编译网络

Keras通过model.compile()编译网络,其可以定义损失函数、优化器、评估指标等参数。

model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

这里使用交叉熵categorical_crossentropy作为损失函数,这是最常用的多分类任务的损失函数,常搭配softmax激活函数使用。

优化器我们使用自适应矩估计:Adam,Adam简直不要太好用!!!

评价指标我们使用精度:accuracy

6.2 训练网络

Keras可以通过多种函数训练网络,这里我们使用model.fit()训练网络模型,函数中可以定义训练集数据与训练集标签,验证集数据与验证集标签、训练批次、批处理大小等。

train_history = model.fit(x_train, y_train, validation_data=(x_val, y_val), epochs=20, batch_size=32, verbose=2)

这里返回值train_history中包含了训练过程的许多信息,例如训练损失和训练精度等。

接下来网络就会开始训练,训练过程如下:

Epoch 1/20
1563/1563 - 9s - loss: 0.1665 - accuracy: 0.9486 - val_loss: 0.0610 - val_accuracy: 0.9821
Epoch 2/20
1563/1563 - 6s - loss: 0.0524 - accuracy: 0.9833 - val_loss: 0.0473 - val_accuracy: 0.9849
Epoch 3/20
1563/1563 - 6s - loss: 0.0353 - accuracy: 0.9891 - val_loss: 0.0416 - val_accuracy: 0.9873
Epoch 4/20
1563/1563 - 6s - loss: 0.0293 - accuracy: 0.9908 - val_loss: 0.0354 - val_accuracy: 0.9900
Epoch 5/20
1563/1563 - 6s - loss: 0.0195 - accuracy: 0.9939 - val_loss: 0.0372 - val_accuracy: 0.9898
Epoch 6/20
1563/1563 - 6s - loss: 0.0180 - accuracy: 0.9940 - val_loss: 0.0416 - val_accuracy: 0.9876
Epoch 7/20
1563/1563 - 6s - loss: 0.0150 - accuracy: 0.9953 - val_loss: 0.0425 - val_accuracy: 0.9884
Epoch 8/20
1563/1563 - 6s - loss: 0.0108 - accuracy: 0.9961 - val_loss: 0.0365 - val_accuracy: 0.9908
Epoch 9/20
1563/1563 - 6s - loss: 0.0120 - accuracy: 0.9957 - val_loss: 0.0406 - val_accuracy: 0.9890
Epoch 10/20
1563/1563 - 6s - loss: 0.0087 - accuracy: 0.9970 - val_loss: 0.0437 - val_accuracy: 0.9893
Epoch 11/20
1563/1563 - 6s - loss: 0.0081 - accuracy: 0.9973 - val_loss: 0.0487 - val_accuracy: 0.9884
Epoch 12/20
1563/1563 - 6s - loss: 0.0067 - accuracy: 0.9978 - val_loss: 0.0470 - val_accuracy: 0.9906
Epoch 13/20
1563/1563 - 6s - loss: 0.0075 - accuracy: 0.9976 - val_loss: 0.0388 - val_accuracy: 0.9905
Epoch 14/20
1563/1563 - 6s - loss: 0.0068 - accuracy: 0.9977 - val_loss: 0.0554 - val_accuracy: 0.9897
Epoch 15/20
1563/1563 - 6s - loss: 0.0056 - accuracy: 0.9981 - val_loss: 0.0512 - val_accuracy: 0.9908
Epoch 16/20
1563/1563 - 6s - loss: 0.0058 - accuracy: 0.9981 - val_loss: 0.0479 - val_accuracy: 0.9914
Epoch 17/20
1563/1563 - 6s - loss: 0.0056 - accuracy: 0.9980 - val_loss: 0.0482 - val_accuracy: 0.9912
Epoch 18/20
1563/1563 - 6s - loss: 0.0057 - accuracy: 0.9982 - val_loss: 0.0528 - val_accuracy: 0.9904
Epoch 19/20
1563/1563 - 6s - loss: 0.0046 - accuracy: 0.9985 - val_loss: 0.0538 - val_accuracy: 0.9895
Epoch 20/20
1563/1563 - 6s - loss: 0.0038 - accuracy: 0.9986 - val_loss: 0.0581 - val_accuracy: 0.9900

6.3 训练过程可视化

我们可以通过图的方式展示神经网路在训练时的损失与精度的变化,我们定义函数:

def show_train_history(train_history, train, validation):
    plt.plot(train_history.history[train])
    plt.plot(train_history.history[validation])
    plt.title('Train History')
    plt.ylabel(train)
    plt.xlabel('Epoch')
    plt.legend(['train', 'validation'], loc='best')
    plt.show()

我们调用该函数:

show_train_history(train_history, 'accuracy', 'val_accuracy')
show_train_history(train_history, 'loss', 'val_loss')

在这里插入图片描述
上图分别表示网络训练过程中在训练集与验证集上的精度与损失的变化折现图。通过折线图我们可以判断网络是否发生过拟合等情况。

6.4 保存训练好的网络模型

Keras有多种保存网络模型的函数,这里我们使用model.save()

model.save('handwritten_numeral_recognition.h5')

.h5模型中包含模型结构、模型权重、模型编译信息等。

七、网络预测

7.1 测试集预测结果

Keras通过函数model.evaluate()测试神经网路在测试集上的情况。

score = model.evaluate(x_test, y_test)

score中包含了测试集上的损失与精度信息,我们打印一下:

print('Test loss:', score[0])
print('Test accuracy:', score[1])

输出打印结果:

Test loss: 0.0538315623998642
Test accuracy: 0.9905999898910522

从结果我们可知,我们的神经网路在测试集上的精度可以达到99%,说明网络还是不错的。

我们通过model.predict()对测试集图像进行预测:

predictions = model.predict(x_test)
predictions = np.argmax(predictions, axis=1)
print('前20张图片预测结果:', predictions[:20])

前20张图像的预测结果如下:

前20张图片预测结果: [7 2 1 0 4 1 4 9 5 9 0 6 9 0 1 5 9 7 3 4]

7.2 测试集预测结果图像可视化

我们可以像第三部分那样,构造一个函数可以既显示图片,又能显示图像预测的结果,定义以下函数:

def mnist_visualize_multiple_predict(start, end, length, width):

    for i in range(start, end):
        plt.subplot(length, width, 1 + i)
        plt.imshow(x_test_original[i], cmap=plt.get_cmap('gray'))
        title_true = 'true=' + str(y_test_original[i])
        title_prediction = ',' + 'prediction' + str(model.predict_classes(np.expand_dims(x_test[i], axis=0)))
        title = title_true + title_prediction
        plt.title(title)
        plt.xticks([])
        plt.yticks([])
    plt.show()

调用该函数:

mnist_visualize_multiple_predict(start=0, end=9, length=3, width=3)

在这里插入图片描述
我们可以得到测试集上图像的真实标签与预测标签。

第9张图像已经很抽象了,网络仍能精准判别出数字是5。

7.3 显示混淆矩阵

通过建立混淆矩阵可以更直观的感知每一种类别的误差。
首先构造混淆矩阵:

cm = confusion_matrix(y_test_original, predictions)
cm = pd.DataFrame(cm)

然后我们构造一个类名:

class_names = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']

最后我们定义混淆矩阵可视化函数:

def plot_confusion_matrix(cm):
    plt.figure(figsize=(10, 10))
    sns.heatmap(cm, cmap='Oranges', linecolor='black', linewidth=1, annot=True, fmt='', xticklabels=class_names, yticklabels=class_names)
    plt.xlabel("Predicted")
    plt.ylabel("Actual")
    plt.title("Confusion Matrix")
    plt.show()

我们调用这个函数:

plot_confusion_matrix(cm)

可视化结果如图:
在这里插入图片描述

八、完整程序

from keras.datasets import mnist
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from sklearn.metrics import confusion_matrix
import seaborn as sns
from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D, Flatten, Dense
from keras.utils import np_utils
from keras.utils.vis_utils import plot_model
import tensorflow as tf
import os
import keras
config = tf.compat.v1.ConfigProto()
config.gpu_options.allow_growth = True
sess = tf.compat.v1.Session(config=config)

# 设定随机数种子,使得每个网络层的权重初始化一致
# np.random.seed(10)

# x_train_original和y_train_original代表训练集的图像与标签, x_test_original与y_test_original代表测试集的图像与标签
(x_train_original, y_train_original), (x_test_original, y_test_original) = mnist.load_data()

"""
数据可视化
"""

# 单张图像可视化
def mnist_visualize_single(mode, idx):
    if mode == 0:
        plt.imshow(x_train_original[idx], cmap=plt.get_cmap('gray'))
        title = 'label=' + str(y_train_original[idx])
        plt.title(title)
        plt.xticks([])  # 不显示x轴
        plt.yticks([])  # 不显示y轴
        plt.show()
    else:
        plt.imshow(x_test_original[idx], cmap=plt.get_cmap('gray'))
        title = 'label=' + str(y_test_original[idx])
        plt.title(title)
        plt.xticks([])  # 不显示x轴
        plt.yticks([])  # 不显示y轴
        plt.show()

# 多张图像可视化
def mnist_visualize_multiple(mode, start, end, length, width):
    if mode == 0:
        for i in range(start, end):
            plt.subplot(length, width, 1 + i)
            plt.imshow(x_train_original[i], cmap=plt.get_cmap('gray'))
            title = 'label=' + str(y_train_original[i])
            plt.title(title)
            plt.xticks([])
            plt.yticks([])
        plt.show()
    else:
        for i in range(start, end):
            plt.subplot(length, width, 1 + i)
            plt.imshow(x_test_original[i], cmap=plt.get_cmap('gray'))
            title = 'label=' + str(y_test_original[i])
            plt.title(title)
            plt.xticks([])
            plt.yticks([])
        plt.show()

# 原始数据量可视化
print('训练集图像的尺寸:', x_train_original.shape)
print('训练集标签的尺寸:', y_train_original.shape)
print('测试集图像的尺寸:', x_test_original.shape)
print('测试集标签的尺寸:', y_test_original.shape)

"""
数据预处理
"""

# 从训练集中分配验证集
x_val = x_train_original[50000:]
y_val = y_train_original[50000:]
x_train = x_train_original[:50000]
y_train = y_train_original[:50000]
# 打印验证集数据量
print('验证集图像的尺寸:', x_val.shape)
print('验证集标签的尺寸:', y_val.shape)
print('======================')

# 将图像转换为四维矩阵(nums,rows,cols,channels), 这里把数据从unint类型转化为float32类型, 提高训练精度。
x_train = x_train.reshape(x_train.shape[0], 28, 28, 1).astype('float32')
x_val = x_val.reshape(x_val.shape[0], 28, 28, 1).astype('float32')
x_test = x_test_original.reshape(x_test_original.shape[0], 28, 28, 1).astype('float32')

#原始图像的像素灰度值为0-255,为了提高模型的训练精度,通常将数值归一化映射到0-1。
x_train = x_train / 255
x_val = x_val / 255
x_test = x_test / 255

print('训练集传入网络的图像尺寸:', x_train.shape)
print('验证集传入网络的图像尺寸:', x_val.shape)
print('测试集传入网络的图像尺寸:', x_test.shape)

# 图像标签一共有10个类别即0-9,这里将其转化为独热编码(One-hot)向量
y_train = np_utils.to_categorical(y_train)
y_val = np_utils.to_categorical(y_val)
y_test = np_utils.to_categorical(y_test_original)

"""
定义网络模型
"""

def CNN_model():

    model = Sequential()
    model.add(Conv2D(filters=16, kernel_size=(5, 5), activation='relu', input_shape=(28, 28, 1)))
    model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))
    model.add(Conv2D(filters=32, kernel_size=(5, 5), activation='relu', input_shape=(28, 28, 1)))
    model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))
    model.add(Flatten())
    model.add(Dense(100, activation='relu'))
    model.add(Dense(10, activation='softmax'))

    print(model.summary())
    return model

"""
训练网络
"""

model = CNN_model()

# 模型网络结构图输出
plot_model(model, to_file='CNN_model.png', show_shapes=True, show_layer_names=True, rankdir='TB')
plt.figure(figsize=(10, 10))
img = plt.imread('CNN_model.png')
plt.imshow(img)
plt.axis('off')
plt.show()

# 编译网络(定义损失函数、优化器、评估指标)
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

# 开始网络训练(定义训练数据与验证数据、定义训练代数,定义训练批大小)
train_history = model.fit(x_train, y_train, validation_data=(x_val, y_val), epochs=20, batch_size=32, verbose=2)

# 模型保存
model.save('handwritten_numeral_recognition.h5')

# 定义训练过程可视化函数(训练集损失、验证集损失、训练集精度、验证集精度)
def show_train_history(train_history, train, validation):
    plt.plot(train_history.history[train])
    plt.plot(train_history.history[validation])
    plt.title('Train History')
    plt.ylabel(train)
    plt.xlabel('Epoch')
    plt.legend(['train', 'validation'], loc='best')
    plt.show()

show_train_history(train_history, 'accuracy', 'val_accuracy')
show_train_history(train_history, 'loss', 'val_loss')

# 输出网络在测试集上的损失与精度
score = model.evaluate(x_test, y_test)
print('Test loss:', score[0])
print('Test accuracy:', score[1])

# 测试集结果预测
predictions = model.predict(x_test)
predictions = np.argmax(predictions, axis=1)
print('前20张图片预测结果:', predictions[:20])

# 预测结果图像可视化
def mnist_visualize_multiple_predict(start, end, length, width):

    for i in range(start, end):
        plt.subplot(length, width, 1 + i)
        plt.imshow(x_test_original[i], cmap=plt.get_cmap('gray'))
        title_true = 'true=' + str(y_test_original[i])
        title_prediction = ',' + 'prediction' + str(model.predict_classes(np.expand_dims(x_test[i], axis=0)))
        title = title_true + title_prediction
        plt.title(title)
        plt.xticks([])
        plt.yticks([])
    plt.show()

mnist_visualize_multiple_predict(start=0, end=9, length=3, width=3)

# 混淆矩阵
cm = confusion_matrix(y_test_original, predictions)
cm = pd.DataFrame(cm)
class_names = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']

def plot_confusion_matrix(cm):
    plt.figure(figsize=(10, 10))
    sns.heatmap(cm, cmap='Oranges', linecolor='black', linewidth=1, annot=True, fmt='', xticklabels=class_names, yticklabels=class_names)
    plt.xlabel("Predicted")
    plt.ylabel("Actual")
    plt.title("Confusion Matrix")
    plt.show()
    
plot_confusion_matrix(cm)

九、总结

??到此,深度学习的第二篇博文就完成了,这也是我写的第一个keras实战博文,从构思到跑程序再到完成这篇博文用了整整4个小时,肩膀已经巨酸,要去休息加干饭。

??其实有很多知识点限于篇幅原因没有详细介绍。例如Adam优化器为什么常用?为什么使用独热编码等,如果有不懂的小伙伴可以私聊我,或者有机会我会继续介绍相关知识。

??博主水平有限,如果有不对的地方还望多多指教,最后希望这篇文章可以帮助到任何一位想进入深度学习的伙伴!!!

  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2021-11-20 18:23:44  更:2021-11-20 18:24:16 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 4:18:08-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码