学人工智能要学些什么?

学人工智能要学些什么?,第1张

、数学基础。数学基础知识蕴含着处理智能问题的基本思想与方法,也是理解复杂算法的必备要素。这一模块覆盖了人工智能必备的数学基础知识,包括线性代数、概率论、最优化方法等。

2、机器学习。机器学习的作用是从数据中习得学习算法,进而解决实际的应用问题,是人工智能的核心内容之一。这一模块覆盖了机器学习中的主要方法,包括线性回归、决策树、支持向量机、聚类等。

3、人工神经网络。作为机器学习的一个分支,神经网络将认知科学引入机器学习中,以模拟生物神经系统对真实世界的交互反应,并取得了良好的效果。这一模块覆盖了神经网络中的基本概念,包括多层神经网络、前馈与反向传播、自组织神经网络等。

4、深度学习。简而言之,深度学习就是包含多个中间层的神经网络,数据爆炸和计算力飙升推动了深度学习的崛起。这一模块覆盖了深度学习的概念与实现,包括深度前馈网络、深度学习中的正则化、自编码器等。

5、神经网络实例。在深度学习框架下,一些神经网络已经被用于各种应用场景,并取得了不俗的效果。这一模块覆盖了几种神经网络实例,包括深度信念网络、卷积神经网络、循环神经网络等。

6、深度学习之外的人工智能。深度学习既有优点也有局限,其他方向的人工智能研究正是有益的补充。这一模块覆盖了与深度学习无关的典型学习方法,包括概率图模型、集群智能、迁移学习、知识图谱等。

7、应用场景。除了代替人类执行重复性的劳动,在诸多实际问题的处理中,人工智能也提供了有意义的尝试。这一模块覆盖了人工智能技术在几类实际任务中的应用,包括计算机视觉、语音处理、对话系统等。

既然用matlab的话rbf神经网络不需要自己写代码,matlab有提供的RBF工具箱

训练命令主要有两个,一个是固定隐含层节点数的指令newrbe,一个是变隐含层节点数的指令newrb预测输出指令和其他神经网络一样,是sim

常用指令输出格式是net = newrbe(P,T,spread);net = newrb(P,T,goal,spread,MN,DF); X = sim(net,xn_test)参数具体格式参看help newrbe;help newrb以及help sim,参数物理意义参看相关理论,不再赘述了

因为一般不存在局部最小问题,所以不需要使用结构体编辑指令设置初值,如果需要中间过程的原始数据,可以在训练结构体中找到(即为net参数,存储格式为结构体),结构体内部数据的物理意义,参看help help关于rbf神经网络结构体的介绍

MLPClassifier是一个监督学习算法,下图是只有1个隐藏层的MLP模型 ,左侧是输入层,右侧是输出层。

上图的整体结构可以简单的理解为下图所示:

MLP又名多层感知机,也叫人工神经网络(ANN,Artificial Neural Network),除了输入输出层,它中间可以有多个隐藏层,如果没有隐藏层即可解决线性可划分的数据问题。最简单的MLP模型只包含一个隐藏层,即三层的结构,如上图。

从上图可以看到,多层感知机的层与层之间是全连接的(全连接的意思就是:上一层的任何一个神经元与下一层的所有神经元都有连接)。多层感知机最底层是输入层,中间是隐藏层,最后是输出层。

输入层没什么好说,你输入什么就是什么,比如输入是一个n维向量,就有n个神经元。

隐藏层的神经元怎么得来?首先它与输入层是全连接的,假设输入层用向量X表示,则隐藏层的输出就是

f(W1X+b1),W1是权重(也叫连接系数),b1是偏置,函数f 可以是常用的sigmoid函数或者tanh函数:

最后就是输出层,输出层与隐藏层是什么关系?其实隐藏层到输出层可以看成是一个多类别的逻辑回归,也即softmax回归,所以输出层的输出就是softmax(W2X1+b2),X1表示隐藏层的输出f(W1X+b1)。

MLP整个模型就是这样子的,上面说的这个三层的MLP用公式总结起来就是,函数G是softmax

因此,MLP所有的参数就是各个层之间的连接权重以及偏置,包括W1、b1、W2、b2。对于一个具体的问题,怎么确定这些参数?求解最佳的参数是一个最优化问题,解决最优化问题,最简单的就是梯度下降法了(sgd):首先随机初始化所有参数,然后迭代地训练,不断地计算梯度和更新参数,直到满足某个条件为止(比如误差足够小、迭代次数足够多时)。这个过程涉及到代价函数、规则化(Regularization)、学习速率(learning rate)、梯度计算等。

下面写了一个超级简单的实例,训练和测试数据是mnist手写识别数据集:

from sklearnneural_network import MLPClassifier

import gzip

import pickle

with gzipopen('/mnistpklgz') as f_gz:

    train_data,valid_data,test_data = pickleload(f_gz)

clf = MLPClassifier(solver='sgd',activation = 'identity',max_iter = 10,alpha = 1e-5,hidden_layer_sizes = (100,50),random_state = 1,verbose = True)

clffit(train_data[0][:10000],train_data[1][:10000])

print clfpredict(test_data[0][:10])

print(clfscore(test_data[0][:100],test_data[1][:100]))

print(clfpredict_proba(test_data[0][:10]))

参数说明:

参数说明: 

1 hidden_layer_sizes :例如hidden_layer_sizes=(50, 50),表示有两层隐藏层,第一层隐藏层有50个神经元,第二层也有50个神经元。 

2 activation :激活函数,{‘identity’, ‘logistic’, ‘tanh’, ‘relu’}, 默认relu 

- identity:f(x) = x 

- logistic:其实就是sigmod,f(x) = 1 / (1 + exp(-x)) 

- tanh:f(x) = tanh(x) 

- relu:f(x) = max(0, x) 

3 solver: {‘lbfgs’, ‘sgd’, ‘adam’}, 默认adam,用来优化权重 

- lbfgs:quasi-Newton方法的优化器 

- sgd:随机梯度下降 

- adam: Kingma, Diederik, and Jimmy Ba提出的机遇随机梯度的优化器 

注意:默认solver ‘adam’在相对较大的数据集上效果比较好(几千个样本或者更多),对小数据集来说,lbfgs收敛更快效果也更好。 

4 alpha :float,可选的,默认00001,正则化项参数 

5 batch_size : int , 可选的,默认’auto’,随机优化的minibatches的大小batch_size=min(200,n_samples),如果solver是’lbfgs’,分类器将不使用minibatch 

6 learning_rate :学习率,用于权重更新,只有当solver为’sgd’时使用,{‘constant’,’invscaling’, ‘adaptive’},默认constant 

- ‘constant’: 有’learning_rate_init’给定的恒定学习率 

- ‘incscaling’:随着时间t使用’power_t’的逆标度指数不断降低学习率learning_rate_ ,effective_learning_rate = learning_rate_init / pow(t, power_t) 

- ‘adaptive’:只要训练损耗在下降,就保持学习率为’learning_rate_init’不变,当连续两次不能降低训练损耗或验证分数停止升高至少tol时,将当前学习率除以5 

7 power_t: double, 可选, default 05,只有solver=’sgd’时使用,是逆扩展学习率的指数当learning_rate=’invscaling’,用来更新有效学习率。 

8 max_iter: int,可选,默认200,最大迭代次数。 

9 random_state:int 或RandomState,可选,默认None,随机数生成器的状态或种子。 

10 shuffle: bool,可选,默认True,只有当solver=’sgd’或者‘adam’时使用,判断是否在每次迭代时对样本进行清洗。 

11 tol:float, 可选,默认1e-4,优化的容忍度 

12 learning_rate_int:double,可选,默认0001,初始学习率,控制更新权重的补偿,只有当solver=’sgd’ 或’adam’时使用。 

14 verbose : bool, 可选, 默认False,是否将过程打印到stdout 

15 warm_start : bool, 可选, 默认False,当设置成True,使用之前的解决方法作为初始拟合,否则释放之前的解决方法。 

16 momentum : float, 默认 09,动量梯度下降更新,设置的范围应该00-10 只有solver=’sgd’时使用 

17 nesterovs_momentum : boolean, 默认True, Whether to use Nesterov’s momentum 只有solver=’sgd’并且momentum > 0使用 

18 early_stopping : bool, 默认False,只有solver=’sgd’或者’adam’时有效,判断当验证效果不再改善的时候是否终止训练,当为True时,自动选出10%的训练数据用于验证并在两步连续迭代改善,低于tol时终止训练。 

19 validation_fraction : float, 可选, 默认 01,用作早期停止验证的预留训练数据集的比例,早0-1之间,只当early_stopping=True有用 

20 beta_1 : float, 可选, 默认09,只有solver=’adam’时使用,估计一阶矩向量的指数衰减速率,[0,1)之间 

21 beta_2 : float, 可选, 默认0999,只有solver=’adam’时使用估计二阶矩向量的指数衰减速率[0,1)之间 

22 epsilon : float, 可选, 默认1e-8,只有solver=’adam’时使用数值稳定值。 

属性说明: 

- classes_:每个输出的类标签 

- loss_:损失函数计算出来的当前损失值 

- coefs_:列表中的第i个元素表示i层的权重矩阵 

- intercepts_:列表中第i个元素代表i+1层的偏差向量 

- n_iter_ :迭代次数 

- n_layers_:层数 

- n_outputs_:输出的个数 

- out_activation_:输出激活函数的名称。 

方法说明: 

- fit(X,y):拟合 

- get_params([deep]):获取参数 

- predict(X):使用MLP进行预测 

- predic_log_proba(X):返回对数概率估计 

- predic_proba(X):概率估计 

- score(X,y[,sample_weight]):返回给定测试数据和标签上的平均准确度 

-set_params(params):设置参数。

用keras框架较为方便

首先安装anaconda,然后通过pip安装keras

以下转自wphh的博客。

#coding:utf-8

'''

    GPU run command:

        THEANO_FLAGS=mode=FAST_RUN,device=gpu,floatX=float32 python cnnpy

    CPU run command:

        python cnnpy

20160606更新:

这份代码是keras开发初期写的,当时keras还没有现在这么流行,文档也还没那么丰富,所以我当时写了一些简单的教程。

现在keras的API也发生了一些的变化,建议及推荐直接上kerasio看更加详细的教程。

'''

#导入各种用到的模块组件

from __future__ import absolute_import

from __future__ import print_function

from keraspreprocessingimage import ImageDataGenerator

from kerasmodels import Sequential

from keraslayerscore import Dense, Dropout, Activation, Flatten

from keraslayersadvanced_activations import PReLU

from keraslayersconvolutional import Convolution2D, MaxPooling2D

from kerasoptimizers import SGD, Adadelta, Adagrad

from kerasutils import np_utils, generic_utils

from sixmoves import range

from data import load_data

import random

import numpy as np

nprandomseed(1024)  # for reproducibility

#加载数据

data, label = load_data()

#打乱数据

index = [i for i in range(len(data))]

randomshuffle(index)

data = data[index]

label = label[index]

print(datashape[0], ' samples')

#label为0~9共10个类别,keras要求格式为binary class matrices,转化一下,直接调用keras提供的这个函数

label = np_utilsto_categorical(label, 10)

###############

#开始建立CNN模型

###############

#生成一个model

model = Sequential()

#第一个卷积层,4个卷积核,每个卷积核大小55。1表示输入的的通道,灰度图为1通道。

#border_mode可以是valid或者full,具体看这里说明:http://deeplearningnet/software/theano/library/tensor/nnet/convhtml#theanotensornnetconvconv2d

#激活函数用tanh

#你还可以在modeladd(Activation('tanh'))后加上dropout的技巧: modeladd(Dropout(05))

modeladd(Convolution2D(4, 5, 5, border_mode='valid',input_shape=(1,28,28))) 

modeladd(Activation('tanh'))

#第二个卷积层,8个卷积核,每个卷积核大小33。4表示输入的特征图个数,等于上一层的卷积核个数

#激活函数用tanh

#采用maxpooling,poolsize为(2,2)

modeladd(Convolution2D(8, 3, 3, border_mode='valid'))

modeladd(Activation('tanh'))

modeladd(MaxPooling2D(pool_size=(2, 2)))

#第三个卷积层,16个卷积核,每个卷积核大小33

#激活函数用tanh

#采用maxpooling,poolsize为(2,2)

modeladd(Convolution2D(16, 3, 3, border_mode='valid')) 

modeladd(Activation('relu'))

modeladd(MaxPooling2D(pool_size=(2, 2)))

#全连接层,先将前一层输出的二维特征图flatten为一维的。

#Dense就是隐藏层。16就是上一层输出的特征图个数。4是根据每个卷积层计算出来的:(28-5+1)得到24,(24-3+1)/2得到11,(11-3+1)/2得到4

#全连接有128个神经元节点,初始化方式为normal

modeladd(Flatten())

modeladd(Dense(128, init='normal'))

modeladd(Activation('tanh'))

#Softmax分类,输出是10类别

modeladd(Dense(10, init='normal'))

modeladd(Activation('softmax'))

#############

#开始训练模型

##############

#使用SGD + momentum

#modelcompile里的参数loss就是损失函数(目标函数)

sgd = SGD(lr=005, decay=1e-6, momentum=09, nesterov=True)

modelcompile(loss='categorical_crossentropy', optimizer=sgd,metrics=["accuracy"])

#调用fit方法,就是一个训练过程 训练的epoch数设为10,batch_size为100.

#数据经过随机打乱shuffle=True。verbose=1,训练过程中输出的信息,0、1、2三种方式都可以,无关紧要。show_accuracy=True,训练时每一个epoch都输出accuracy。

#validation_split=02,将20%的数据作为验证集。

modelfit(data, label, batch_size=100, nb_epoch=10,shuffle=True,verbose=1,validation_split=02)

"""

#使用data augmentation的方法

#一些参数和调用的方法,请看文档

datagen = ImageDataGenerator(

        featurewise_center=True, # set input mean to 0 over the dataset

        samplewise_center=False, # set each sample mean to 0

        featurewise_std_normalization=True, # divide inputs by std of the dataset

        samplewise_std_normalization=False, # divide each input by its std

        zca_whitening=False, # apply ZCA whitening

        rotation_range=20, # randomly rotate images in the range (degrees, 0 to 180)

        width_shift_range=02, # randomly shift images horizontally (fraction of total width)

        height_shift_range=02, # randomly shift images vertically (fraction of total height)

        horizontal_flip=True, # randomly flip images

        vertical_flip=False) # randomly flip images

# compute quantities required for featurewise normalization 

# (std, mean, and principal components if ZCA whitening is applied)

datagenfit(data)

for e in range(nb_epoch):

    print('-'40)

    print('Epoch', e)

    print('-'40)

    print("Training")

    # batch train with realtime data augmentation

    progbar = generic_utilsProgbar(datashape[0])

    for X_batch, Y_batch in datagenflow(data, label):

        loss,accuracy = modeltrain(X_batch, Y_batch,accuracy=True)

        progbaradd(X_batchshape[0], values=[("train loss", loss),("accuracy:", accuracy)] )

"""

《深度学习精要(基于R语言)》学习笔记

机器学习主要用于开发和使用那些从原始数据中学习、总结出来的用于进行预测的算法。

深度学习是一种强大的多层架构,可以用于模式识别、信号检测以及分类或预测等多个领域。

神经网络包括一系列的神经元,或者叫作节点,它们彼此连结并处理输入。神经元之间的连结经过加权处理,权重取决于从数据中学习、总结出的使用函数。一组神经元的激活和权重(从数据中自适应地学习)可以提供给其他的神经元,其中一些最终神经元的激活就是预测。

经常选择的激活函数是sigmoid函数以及双曲正切函数tanh,因为径向基函数是有效的函数逼近,所以有时也会用到它们。

权重是从每个隐藏单元到每个输出的路径,对第i个的输出通过(w_i)表示。如创建隐藏层的权重,这些权重也是从数据中学习得到的。分类会经常使用一种最终变换,softmax函数。线性回归经常使用恒等(identity)函数,它返回输入值。权重必须从数据中学习得到,权重为零或接近零基本上等同于放弃不必要的关系。

R中神经网络相关包:

一旦集群完成初始化,可以使用R或本地主机(127001:54321)提供的Web接口与它连接。

如果数据集已经加载到R,使用ash2o()函数:

如果数据没有载入R,可以直接导入到h2o中:

也可以直接导入网络上的文件:

导入基于识别手写体数字,数据集的每一列(即特征),表示图像的一个像素。每张图像都经过标准化处理,转化成同样的大小,所以所有图像的像素个数都相同。第一列包含真实的数据标签,其余各列是黑暗像素的值,它用于分类。

使用caret包训练模型:

生成数据的一组预测,查看柱状图:

跟训练集数据柱状图对比,很明显模型不是最优的。

通过混淆矩阵检查模型性能:

No Information Rate(无信息率)指不考虑任何信息而仅仅通过猜测来决定最频繁的类的准确度期望。在情形“1”中,它在1116%的时间中发生。P值(P-Value [Acc > NIR])检验了观测准确度(Accuracy : 03674)是否显著不同于无信息率(1116%)。

Class: 0的灵敏度(Sensitivity)可以解释为:8907%的数字0被正确地预测为0。特异度(Specificity)可以解释为:9514%的预测为非数字0被预测为不是数字0。

检出率(Detection Rate)是真阳性的百分比,而最后的检出预防度(detection prevalence)是预测为阳性的实例比例,不管它们是否真的为阳性。

平衡准确度(balanced accuracy)是灵敏度和特异度的平均值。

接下来我们通过增加神经元的个数来提升模型的性能,其代价是模型的复杂性会显著增加:

隐藏神经元的数量从5个增加到10个,样本内性能的总准确度从3674% 提升到了 654%。我们继续增加隐藏神经元的数量:

增加到40个神经元后准确度跟10个神经元的一样,还是654%。如果是商业问题,还需要继续调节神经元的数量和衰变率。但是作为学习,模型对数字9的表现比较差,对其他数字都还行。

RSNNS包提供了使用斯图加特神经网络仿真器(Stuttgart Neural Network Simulator , SNNS)模型的接口,但是,对基本的、单隐藏层的、前馈的神经网络,我们可以使用mlp()这个更为方便的封装函数,它的名称表示多层感知器(multi-layer perceptron)。

RSNNS包要求输入为矩阵、响应变量为一个哑变量的 矩阵 ,因此每个可能的类表示成矩阵列中的 0/1 编码。

通过decodeClassLabels()函数可以很方便的将数据转换为哑变量矩阵。

预测结果的值为1-10,但是实际值为0-9,所以在生成混淆矩阵时,需要先减去1:

RSNNS包的学习算法使用了相同数目的隐藏神经元,计算结果的性能却有极大提高。

函数I()有两个作用:

1在对dataframe的调用中将对象包含在I()中来保护它,防止字符向量到factor的转换和名称的删除,并确保矩阵作为单列插入。

2在formula函数中,它被用来禁止将“+”、“-”、“”和“^”等运算符解释为公式运算符,因此它们被用作算术运算符。

从RSNNS包返回的预测值(predml4)中可以看到,一个观测可能有40%的概率成为“5”,20%的概率成为“6”,等等。最简单的方法就是基于高预测概率来对观测进行分类。RSNNS包有一种称为赢者通吃(winner takes all,WTA)的方法,只要没有关系就选择概率最高的类,最高的概率高于用户定义的阈值(这个阈值可以是0),而其他类的预测概率都低于最大值减去另一个用户定义的阈值,否则观测的分类就不明了。如果这两个阈值都是0(缺省),那么最大值必然存在并且唯一。这种方法的优点是它提供了某种质量控制。

但是在实际应用中,比如一个医学背景下,我们收集了病人的多种生物指标和基因信息,用来分类确定他们是否健康,是否有患癌症的风险,是否有患心脏病的风险,即使有40%的患癌概率也需要病人进一步做检查,即便他健康的概率是60%。RSNNS包中还提供一种分类方法称为“402040”,如果一个值高于用户定义的阈值,而所有的其他值低于用户定义的另一个阈值。如果多个值都高于第一个阈值,或者任何值都不低于第二个阈值,我们就把观测定性为未知的。这样做的目的是再次给出了某种质量控制。

“0”分类表示未知的预测。

通常来说,过拟合指模型在训练集上的性能优于测试集。过拟合发生在模型正好拟合了训练数据的噪声部分的时候。因为考虑了噪声,它似乎更准确,但一个数据集和下一个数据集的噪声不同,这种准确度不能运用于除了训练数据之外的任何数据 — 它没有一般化。

使用RSNNS模型对样本外数据预测:

模型在第一个5000行上的准确度为851%,在第二个5000行上的准确度减少为80%,损失超过5%,换句话说,使用训练数据来评价模型性能导致了过度乐观的准确度估计,过度估计是5%。

这个问题我们后面再处理。

这个不能直接调用matlab自带的SVM工具箱,要安装libsvm工具箱才可以使用,你看第12章,《第12章 初始SVM分类与回归》,要按12章装了SVM工具箱, 才能用。我自己也没弄过,为了找到答案,我还去下了代码来捣鼓,不过最后没找到12章的书,所以也不知作者用的是哪个版本的LIBSVM,没法实验,只能帮你到这了哥们,希望采纳。

%人脸识别模型,脸部模型自己找吧。

function mytest()

clc;

images=[ ];

M_train=3;%表示人脸

N_train=5;%表示方向

sample=[];

pixel_value=[];

sample_number=0;

for j=1:N_train

for i=1:M_train

str=strcat('Images\',num2str(i),'_',num2str(j),'bmp'); %读取图像,连接字符串形成图像的文件名。

img= imread(str);

[rows cols]= size(img);%获得图像的行和列值。

img_edge=edge(img,'Sobel');

%由于在分割中我们可以看到这个人脸的眼睛部分也就是位于分割后的第二行中,位置变化比较大,而且眼睛边缘检测效果很好

sub_rows=floor(rows/6);%最接近的最小整数,分成6行

sub_cols=floor(cols/8);%最接近的最小整数,分成8列

sample_num=M_trainN_train;%前5个是第一幅人脸的5个角度

sample_number=sample_number+1;

for subblock_i=1:8 %因为这还在i,j的循环中,所以不可以用i

block_num=subblock_i;

pixel_value(sample_number,block_num)=0;

for ii=sub_rows:(2sub_rows)

for jj=(subblock_i-1)sub_cols+1:subblock_isub_cols

pixel_value(sample_number,block_num)=pixel_value(sample_number,block_num)+img_edge(ii,jj);

end

end

end

end

end

%将特征值转换为小于1的值

max_pixel_value=max(pixel_value);

max_pixel_value_1=max(max_pixel_value);

for i=1:3

mid_value=10^i;

if(((max_pixel_value_1/mid_value)>1)&&((max_pixel_value_1/mid_value)<10))

multiple_num=1/mid_value;

pixel_value=pixel_valuemultiple_num;

break;

end

end

% T 为目标矢量

t=zeros(3,sample_number);

%因为有五类,所以至少用3个数表示,5介于2的2次方和2的3次方之间

for i=1:sample_number

% if((mod(i,5)==1)||(mod(i,5)==4)||(mod(i,5)==0))

if(i<=3)||((i>9)&&(i<=12))||((i>12)&&(i<=15))

t(1,i)=1;

end

%if((mod(i,5)==2)||(mod(i,5)==4))

if((i>3)&&(i<=6))||((i>9)&&(i<=12))

t(2,i)=1;

end

%if((mod(i,5)==3)||(mod(i,5)==0))

if((i>6)&&(i<=9))||((i>12)&&(i<=15))

t(3,i)=1;

end

end

% NEWFF——生成一个新的前向神经网络

% TRAIN——对 BP 神经网络进行训练

% SIM——对 BP 神经网络进行仿真

% 定义训练样本

% P 为输入矢量

P=pixel_value'

% T 为目标矢量

T=t

size(P)

size(T)

% size(P)

% size(T)

% 创建一个新的前向神经网络

net_1=newff(minmax(P),[10,3],{'tansig','purelin'},'traingdm')

% 当前输入层权值和阈值

inputWeights=net_1IW{1,1}

inputbias=net_1b{1}

% 当前网络层权值和阈值

layerWeights=net_1LW{2,1}

layerbias=net_1b{2}

% 设置训练参数

net_1trainParamshow = 50;

net_1trainParamlr = 005;

net_1trainParammc = 09;

net_1trainParamepochs = 10000;

net_1trainParamgoal = 1e-3;

% 调用 TRAINGDM 算法训练 BP 网络

[net_1,tr]=train(net_1,P,T);

% 对 BP 网络进行仿真

A = sim(net_1,P);

% 计算仿真误差

E = T - A;

MSE=mse(E)

x=[014 0 1 1 0 1 1 12]';

sim(net_1,x)

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/zaji/12177606.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-21
下一篇2023-05-21

发表评论

登录后才能评论

评论列表(0条)

    保存