Google 的神经网络 图像识别生成图像 是怎么做到的

谷歌AlphaGo的深度神经网络 未来可以这样实现_网易科技
谷歌AlphaGo的深度神经网络 未来可以这样实现
用微信扫码二维码
分享至好友和朋友圈
(原标题:类似谷歌AlphaGo的深度神经网络,未来可能通过“片上学习”实现)
今年初谷歌AlphaGo与围棋冠军李世石的人机大战,让人们对人工智能的关注度提升到了前所未有的高度,正所谓“外行看热闹、内行看门道”,AlphaGo获胜的背后离不开谷歌开发的深度神经网络,而这正是人工智能机器学习当中重要的组成部分。AlphaGo在对战时,是采用一种“在线学习”(On-Line Learning)的模式,意思就是说AlphaGo的服务器在美国中西部,通过谷歌云服务连接到韩国首尔的对局室,谷歌总部团队必须确保AlphaGo与谷歌的服务器连接顺利,在机器学习领域,除了这种目前较为主流的“在线学习”,还有一种效率更高并且直接在硬件端完成机器学习的方式——片上学习,简单讲就是字面所传达的意思,在芯片上进行机器学习。在了解“片上学习”之前,我们有必要回顾一下计算机的工作结构。几十年前,美籍匈牙利科学家冯·诺依曼曾提出了以自己名字命名的“冯·诺依曼体系”,这种体系结构下,计算机的指令和数据采用0和1的二进制,处理任务按照固定程序顺序进行,也就是所谓的“串联”。而人脑处理事情为“并联”模式,人类可以同步处理看到、听到的内容,并且基于人类的“自我学习”能力,完成一次判断。比如,心智正常的人,面对一本杂志与一份报纸,可以在一瞬间分辨出来,这是人类大脑内的视觉图像信息神经元、逻辑思维判断神经元与人类“自我学习”能力,在一瞬间里“并行”作业的结果。“冯·诺依曼体系”沿用了半个世纪,但在接下来的人工智能时代,计算机需要尽可能地模拟人类大脑神经元和突触处理信息的方式,如视觉、听觉,随后,接受到的信息、图片和声音又能改变神经元之间的联系,这整个过程就是机器学习的过程。机器学习的过程只有通过神经网络的计算才能实现,为了处理神经网络所带来的指数级数据增长,人们开始研发专门的芯片,才有了后来的“片上学习”。“片上学习”的进化历程从全球范围内来看,已有多家公司致力于“在线学习”的算法研究,在视觉、声音、大数据等领域人工智能均有一些落地的案例,相比之下“片上学习”在严苛的硬件环境中依旧研究进展缓慢。比如IBM的TrueNorth项目,这个以神经形态工程学设计的CMOS芯片,包含了4096个硬件核心,每个核心包含256个可编程的神经元芯片,拥有超过100万的神经元。在钛媒体创新产品平台“我造社区”当中,有一家名为“西井科技”的神经形态实验室同样致力于此。今年5月份,这家公司宣布研发出了全球首块5000万“神经元”类脑芯片——Westwell Brain,可模拟出5000万级别的“神经元”,总计有50多亿“神经突触”。作为对比,人类大脑的神经元大约800亿--1000亿个,有5000万个神经元的电脑虽然不能与人类大脑相提并论,但它已经可以实现一些浅层的“片上学习”了,比如分辨画作流派这种事情。2014年,加州理工大学Sergey Karayev等人收集了Wiki-paintings画作,以此来检验机器学习的成果。Westwell Brain“片上学习”Wiki系统的测试成绩为1秒自动完成1000多张图片的分类,正确率接近100%。打个比方,“片上学习”Wiki系统就好像学生身边时刻跟随着一位“私教”,直接在芯片上边学习边测试训练成果,最大的优势是实现“无网络”情况下的“自我学习、自我实时提高”。而“在线学习”则好比学生定期去“学校”上课,回家后做作业来测试学习效果,再将优化过的模型灌输在硬件中,每一次新的学习都需通过网络、云端等手段重新进行传输、迁移。
因为“片上学习”可以实现本地化学习,从而帮助机器大幅度提升效率,提高运算速度。在网络环境相对严苛或有限的情况下,“片上学习”的芯片消耗的带宽和流量更少,大幅降低云端服务器的通讯成本,且耗时更少。从技术角度来看,“片上学习”的芯片的确有很多优势,它可以直接在硬件上完成学习与测试,进而让基础算法的研发迭代,产品的升级有着更短的周期和更高的效率,并且消耗更少的能源。但另一方面,“片上学习”还没有特定的标准,据西井科技相关负责人介绍,全球从事此领域研究的公司仅在个位数,相关从业人员也极为紧缺,如何使用“片上学习”芯片的技术进行具体场景的商业化落地还存在很大挑战。
本文来源:钛媒体
责任编辑:丁广胜_NT1941
用微信扫码二维码
分享至好友和朋友圈
加载更多新闻
热门产品:   
:        
:         
热门影院:
阅读下一篇
用微信扫描二维码
分享至好友和朋友圈3021人阅读
机器学习(15)
转载请注明作者:
Github工程地址:
欢迎star,有问题可以到讨论
全连接神经网络
辅助阅读: -
Linear Model
加载lesson 1中的数据集
将Data降维成一维,将label映射为one-hot encoding
def reformat(dataset, labels):
dataset = dataset.reshape((-1, image_size * image_size)).astype(np.float32)
labels = (np.arange(num_labels) == labels[:, None]).astype(np.float32)
return dataset, labels
TensorFlow Graph
使用梯度计算train_loss,用tf.Graph()创建一个计算单元
用tf.constant将dataset和label转为tensorflow可用的训练格式(训练中不可修改)
用tf.truncated_normal生成正太分布的数据,作为W的初始值,初始化b为可变的0矩阵
用tf.variable将上面的矩阵转为tensorflow可用的训练格式(训练中可以修改)
用tf.matmul实现矩阵相乘,计算WX+b,这里实际上logit只是一个变量,而非结果
用tf.nn.softmax_cross_entropy_with_logits计算WX+b的结果相较于原来的label的train_loss,并求均值
使用梯度找到最小train_loss
optimizer = tf.train.GradientDescentOptimizer(0.5).minimize(loss)
计算相对valid_dataset和test_dataset对应的label的train_loss
上面这些变量都是一种Tensor的概念,它们是一个个的计算单元,我们在Graph中设置了这些计算单元,规定了它们的组合方式,就好像把一个个门电路串起来那样
TensorFLow Session
Session用来执行Graph里规定的计算,就好像给一个个门电路通上电,我们在Session里,给计算单元冲上数据,That’s Flow.
- 重复计算单元反复训练800次,提高其准确度
- 为了快速查看训练效果,每轮训练只给10000个训练数据(subset),恩,每次都是相同的训练数据
- 将计算单元graph传给session
- 初始化参数
- 传给session优化器 - train_loss的梯度optimizer,训练损失 - train_loss,每次的预测结果,循环执行训练
with tf.Session(graph=graph) as session:
tf.initialize_all_variables().run()
for step in range(num_steps):
_, l, predictions = session.run([optimizer, loss, train_prediction])
- 在循环过程中,W和b会保留,并不断得到修正
- 在每100次循环后,会用验证集进行验证一次,验证也同时修正了一部分参数
valid_prediction.eval()
- 最后用测试集进行测试
- 注意如果lesson 1中没有对数据进行乱序化,可能训练集预测准确度很高,验证集和测试集准确度会很低
这样训练的准确度为83.2%
每次只取一小部分数据做训练,计算loss时,也只取一小部分数据计算loss
对应到程序中,即修改计算单元中的训练数据,
每次输入的训练数据只有128个,随机取起点,取连续128个数据:
offset = (step * batch_size) % (train_labels.shape[0] - batch_size)
batch_data = train_dataset[offset:(offset + batch_size), :]
batch_labels = train_labels[offset:(offset + batch_size), :]
由于这里的数据是会变化的,因此用tf.placeholder来存放这块空间
tf_train_dataset = tf.placeholder(tf.float32,
shape=(batch_size, image_size * image_size))
tf_train_labels = tf.placeholder(tf.float32, shape=(batch_size, num_labels))
计算3000次,训练总数据量为384000,比之前8000000少
准确率提高到86.5%,而且准确率随训练次数增加而提高的速度变快了
上面SGD的模型只有一层WX+b,现在使用一个RELU作为中间的隐藏层,连接两个WX+b
仍然只需要修改Graph计算单元为
Y = W2 * RELU(W1*X + b1) + b2
为了在数学上满足矩阵运算,我们需要这样的矩阵运算:
[n * 10] = RELU([n * 784] · [784 * N] + [n * N]) · [N * 10] + [n * 10]
这里N取1024,即1024个隐藏结点
于是四个参数被修改
weights1 = tf.Variable(
tf.truncated_normal([image_size * image_size, hidden_node_count]))
biases1 = tf.Variable(tf.zeros([hidden_node_count]))
weights2 = tf.Variable(
tf.truncated_normal([hidden_node_count, num_labels]))
biases2 = tf.Variable(tf.zeros([num_labels]))
预测值计算方法改为
ys = tf.matmul(tf_train_dataset, weights1) + biases1
hidden = tf.nn.relu(ys)
logits = tf.matmul(hidden, weights2) + biases2
计算3000次,可以发现准确率一开始提高得很快,后面提高速度变缓,最终测试准确率提高到88.8%
深度神经网络实践
Regularization
在前面实现的中,加Regularization进行约束,采用加l2 norm的方法,进行调节:
代码实现上,只需要对tf_sgd_relu_nn中train_loss做修改即可:
- 可以用tf.nn.l2_loss(t)对一个Tensor对象求l2 norm
- 需要对我们使用的各个W都做这样的计算(参考tensorflow官方)
l2_loss = tf.nn.l2_loss(weights1) + tf.nn.l2_loss(weights2)
添加到train_loss上
这里还有一个重要的点,Hyper Parameter: β
我觉得这是一个拍脑袋参数,取什么值都行,但效果会不同,我这里解释一下我取β=0.001的理由
如果直接将l2_loss加到train_loss上,每次的train_loss都特别大,几乎只取决于l2_loss
为了让原本的train_loss与l2_loss都能较好地对参数调整方向起作用,它们应当至少在同一个量级
观察不加l2_loss,step 0 时,train_loss在300左右
加l2_loss后, step 0 时,train_loss在300000左右
因此给l2_loss乘0.0001使之降到同一个量级
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits, tf_train_labels)) + 0.001 * l2_loss
所有其他参数不变,训练3000次,准确率提高到92.7%
黑魔法之所以为黑魔法就在于,这个参数可以很容易地影响准确率,如果β = 0.002,准确率提高到93.5%
OverFit问题
在训练数据很少的时候,会出现训练结果准确率高,但测试结果准确率低的情况
- 缩小训练数据范围:将把batch数据的起点offset的可选范围变小(只能选择0-1128之间的数据):
offset_range = 1000
offset = (step * batch_size) % offset_range
可以看到,在step500后,训练集就一直是100%,验证集一直是77.6%,准确度无法随训练次数上升,最后的测试准确度是85.4%
采取Dropout方式强迫神经网络学习更多知识
参考中dropout的使用
我们需要丢掉RELU出来的部分结果
调用tf.nn.dropout达到我们的目的:
keep_prob = tf.placeholder(tf.float32)
if drop_out:
hidden_drop = tf.nn.dropout(hidden, keep_prob)
h_fc = hidden_drop
这里的keep_prob是保留概率,即我们要保留的RELU的结果所占比例,tensorflow建议的是,让它作为一个placeholder,在run时传入
当然我们也可以不用placeholder,直接传一个0.5:
if drop_out:
hidden_drop = tf.nn.dropout(hidden, 0.5)
h_fc = hidden_drop
这种训练的结果就是,虽然在step 500对训练集预测没能达到100%(起步慢),但训练集预测率达到100%后,验证集的预测正确率仍然在上升
这就是Dropout的好处,每次丢掉随机的数据,让神经网络每次都学习到更多,但也需要知道,这种方式只在我们有的训练数据比较少时很有效
最后预测准确率为88.0%
Learning Rate Decay
随着训练次数增加,自动调整步长
- 在之前单纯两层神经网络基础上,添加Learning Rate Decay算法
- 使用tf.train.exponential_decay方法,指数下降调整步长,具体使用方法说的特别清楚
- 注意这里面的cur_step传给优化器,优化器在训练中对其做自增计数
- 与之前单纯两层神经网络对比,准确率直接提高到90.6%
Deep Network
增加神经网络层数,增加训练次数到20000
- 为了避免修改网络层数需要重写代码,用循环实现中间层
for i in range(layer_cnt - 2):
y1 = tf.matmul(hidden_drop, weights[i]) + biases[i]
hidden_drop = tf.nn.relu(y1)
if drop_out:
keep_prob += 0.5 * i / (layer_cnt + 1)
hidden_drop = tf.nn.dropout(hidden_drop, keep_prob)
初始化weight在迭代中使用
for i in range(layer_cnt - 2):
if hidden_cur_cnt & 2:
hidden_next_cnt = int(hidden_cur_cnt / 2)
hidden_next_cnt = 2
hidden_stddev = np.sqrt(2.0 / hidden_cur_cnt)
weights.append(tf.Variable(tf.truncated_normal([hidden_cur_cnt, hidden_next_cnt], stddev=hidden_stddev)))
biases.append(tf.Variable(tf.zeros([hidden_next_cnt])))
hidden_cur_cnt = hidden_next_cnt
第一次测试时,用正太分布设置所有W的数值,将标准差设置为1,由于网络增加了一层,寻找step调整方向时具有更大的不确定性,很容易导致loss变得很大
因此需要用stddev调整其标准差到一个较小的范围(怎么调整有许多研究,这里直接找了一个来用)
stddev = np.sqrt(2.0 / n)
启用regular时,也要适当调一下β,不要让它对原本的loss造成过大的影响
DropOut时,因为后面的layer得到的信息越重要,需要动态调整丢弃的比例,到后面的layer,丢弃的比例要减小
keep_prob += 0.5 * i / (layer_cnt + 1)
训练时,调节参数,你可能遇到,
训练到一定程度后,梯度优化器没有什么作用,loss和准确率总是在一定范围内徘徊
官方教程表示最好的训练结果是,准确率97.5%,
我的开启六层神经网络,
启用Regularization、DropOut、Learning Rate Decay,
训练次数20000(应该还有再训练的希望,在这里虽然loss下降很慢了,但仍然在下降),训练结果是,准确率95.2%
觉得我的文章对您有帮助的话,给个可好?
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:60045次
积分:1058
积分:1058
排名:千里之外
原创:27篇
译文:15篇
文章:15篇
阅读:17967
文章:11篇
阅读:29035
(1)(4)(3)(9)(6)(12)(7)(1)后使用快捷导航没有帐号?
GOOGLE 基于神经网络的新型翻译系统是如何实现的
查看: 11331|
评论: 0|原作者: Sachin Joglekar|来自: AI100
摘要: 作为全球 AI 语言翻译服务的领先者之一,2016年9月,谷歌推出了新型的翻译系统,Google Neural Machine Translation(GNMT),能让翻译系统不再像以往那样逐字逐字地翻译,而是从整体上分析句子,大幅提升了机器翻译 ...
作为全球 AI 语言翻译服务的领先者之一,2016年9月,谷歌推出了新型的翻译系统,Google Neural Machine Translation(GNMT),能让翻译系统不再像以往那样逐字逐字地翻译,而是从整体上分析句子,大幅提升了机器翻译的质量。谷歌表示,在一些情况下,GNMT 系统的翻译准确度能够接近人类翻译水平。本篇文章分析了 google 新型翻译系统的技术实现。2016年9月,谷歌推出了新型的翻译系统。自此,翻译系统获得了诸多有意思的发展。本篇文章将用尽可能简洁的语句为大家介绍该新型翻译系统。早期版本的翻译系统是基于短语的机器翻译,即 PBMT(Phrase-based Machine Translation)。PBMT 会将输入的句子分成一组单词或者短语,并将其单独翻译。这显然不是最佳的翻译策略,完全忽略了整个语句的上下文之间的联系。而新型翻译系统使用的是谷歌神经机器翻译,即 GNMT(Google Neural Machine Translation)。该模型改进了传统的 NMT。接下来,让我们看看 GNMT 是如何工作的。编码器在理解编码器之前,我们必须先了解一下 LSTM(Long-Short-Term-Memory) 单元。简单来说,LSTM 单元就是一个具有记忆概念的。LSTM 通常用于“学习”时间序列或者时间数据中的某些模式。在任意指定的点,LSTM 都能接受新的向量输入,并且使用“新的输入+上下文之间的联系”这样的组合生成预期的输出结果:上图中,xt 表示在时间点 t 时的输入数据,ht-1 表示从时间点 t-1 传过来的上下文信息。如果 xt 的维度是 d,那么 ht-1 的维度就是 2d,ht-1 是以下两个向量的级联:在最后一个时间步长 t-1(短期记忆),相同 LSTM 的预期输出;另外一个编码长期记忆的 d 维度向量——也称为单元状态。第二部分通常不用于架构中的下一个组件。相反,它在下一个步骤中会被相同的 LSTM 所使用。通常,在伴有预期输出的同时,我们会使用大量带标签的序列数据来训练 LSTM 模型。这会让我们知道应该重新训练或者保留输入哪些部分,以及如何用数学表达处理 xt 和 ht-1 ,进而得出 ht。如果你想更好地了解 &LSTM,那么我推荐 Christopher Olah 写的这篇博客:http://colah.github.io/posts/2015-08-Understanding-LSTMs/。LSTM 也可以按下图方式展开:不要担心,上图中均为同一个 LSTM 单元的副本(因此采用相同的训练方式),每个单元的输出会反馈到下一个输入。这允许我们可以一次性地输入整个向量集合(实际上,是一整个时间序列),而不用分次单独向 LSTM 的副本中输入。GNMT 的编码器网络本质上是一个堆栈 LSTM。所有水平方向的粉红色/绿色框都是“展开的” LSTM。因此,上图中的模型具有8个堆叠的 LSTM。整个架构的输入是一个句子中的有序集标记,每个都以向量的形式表示。请注意,我说的是标记,而不是一个词。在预处理过程中,GNMT 负责将所有的词分解成标记或者片段,然后将这些标记或者片段输入到神经网络中。这会使框架(至少部分地)能够理解某些没见过的复杂词汇。以“Pteromerhanophobia”词为例,即使你可能并不知道它是什么意思,但是却可以知道这个词具有恐惧的意思,因为它是基于“phobia”标记的。谷歌将这种方法称为 Wordpiece 建模,在其训练阶段,需要从巨大的词库中分解词汇,依据的是统计学习。在使用堆栈 LSTM 的时候,每一层都会根据上一层反馈给它的时间序列得出一个模式。越往上层,越能看到更多的抽象模式,上层的模式是从下层学到的。例如,最底层看到的可能是一组点,接下来的一层将会是一条线,其下一层看到的将是由线条组成的诸个多边形,再接下来,你会看到从多边形中学习得到的一个对象……当然,这是有限制的,取决于使用堆栈 LSTM 的数量和使用方法。并不是 LSTM 越多越好,因为最终你会发现训练这个模型太慢了,而且非常困难。除了堆栈 LSTM,上面的这种架构还有一些有趣的方面。你会看到底部的第二层是绿色的。这是因为箭头——即句子中的标记顺序,在这一层是相反的。这意味着,第二个 LSTM 会以相反的顺序看到整个句子。这样做的原因很简单:当你把某个句子看作整体时,其中任意一个单词的“语境”都将包含其前面和其后面的单词。两个最底层的 LSTM 都将原始的句子作为输入,但是两者的方向是不同的。第三个 LSTM 层从前面两个层获得双向输入——基本上,覆盖了给定句子的正向和逆向语境。之后的每一层,都是如此,从上一层句子中的上下文关系,学习更高级的模式。你可能已经注意到了,从第五层开始出现了“+”号。这是一种残差学习的形式。残差学习从第五层开始发生:对于第 N+1 层,其输入数据是第 N 层和第 N-1 层输出的叠加产物。在的许多应用问题中,残差学习已经被证明可以提高准确性并减少梯度消失(/chap5.html)等问题。直观地说,你可以认为残差学习是一种跨层保存信息的方法。如果你想更好地理解残差学习,那么你可以阅读以下链接中 Quora 问题的答案(/What-is-an-intuitive-explanation-of-Deep-Residual-Networks)。最后,你可以在编码器输入的末尾看到额外的&2es&和&/s&字符。&/s&表示“输入结束”。另一方面,&2es&字符表示的是目标语言——在本次实例中,表示的是西班牙语。把目标语言作为框架的输入,是 GNMT 一个独特之处。这样做的好处是可以提高翻译的质量。注意模块和解码器编码器产生一组有序输出向量(每个输入标记对应一个输出向量)。然后将这些有序向量输入到注意模块和解码器的框架中。在很大程度上,解码器的设计和编码器的设计非常相似,都是堆栈 LSTM 和残差链接。接下来,让我们讨论一下解码器和编码器的不同之处。我已经提到,GNMT 是将整个句子作为输入。然而,直觉上却认为,对于解码器即将产生的所有标记,不应该对输入语句中所有向量(标记)都赋予相等的权重。例如,当你写出故事的一部分时,你的焦点应该缓慢漂移到其余的部分。在 GNMT 中,这项工作由注意模块完成。注意模块获得的输入是编码器的完整输出和解码器的最新向量。这使得它可以“理解”已经翻译了哪些部分,然后指示解码器将注意力转移到编码器输出向量的其他部分。堆栈 LSTM 解码器会根据编码器的输入信息和注意模块的相关命令不断输出向量。这些向量会被输入到 softmax 层中。在这里,你可以将 softmax 层看作是一个概率分布生成器。基于来自最顶层 LSTM 的输入向量,softmax 层为每个可能的输出标记分配概率(请注意,因为目标语言已经提供给了编码器,因此信息已经被传播了)。最后输出获得最大概率的标记。一旦解码器 softmax 层决定当前标记是 &/s&(或句末),那么整个过程将会停止。请注意,解码器解码的步骤数不必完全等同于编码器编码的步骤数,因为在每个计算步骤上都倾注了很多精力。总的来说,这就是你能看到的完整的翻译过程:训练和 Zero-Shot 翻译通过大量的(输入、目标语言)句子集合来训练完整的框架(编码器+注意+解码器)。在某种意义上,在将标记从输入句子转换成适当的向量格式时,体系结构“知道”输入的是什么语言。并且,目标语言也是输入参数的一部分。深度 &LSTM 的高度在于,神经网络会通过一种称为反向传播/梯度下降(Backpropagation/GradientDescent,//backpropagation-for-dummies/)的,来训练这些数据:GNMT 团队还发现了另外一个惊人的现象:如果只是向框架中输入目标语言,就能实现 Zero-Shot 翻译!这意味着:在训练期间,如果我们提供英语→日语和英语→韩语翻译,那么 GNMT 可以自动地实现日语→韩语的翻译,并且完成得非常好!事实上,这也是 GNMT 项目的最大成就。从直觉上来说,编码器产生的是一种通用语言形式。不管我用何种语言来表达“狗”这个单词,最终你都会联想到一只友好的狗狗——从本质上来说,是概念意义上的“狗”。这个“概念”是由编码器产生的,不会考虑语言的限制。事实上,有些文章甚至认为,谷歌的 &AI 发明出了一个独特的语言系统。将目标语言作为输入,这可以让 GNMT 较为容易地使用相同的神经网络利用任意语言对进行训练,同时也使得 Zero-Shot 翻译成为可能。因此,相比以往任何翻译系统,谷歌的新型翻译系统更加接近人类大脑的翻译方式。如果想对该领域有进一步的了解,可以阅读以下文章:First blog post about GNMT onthe Google Research Blog. (Corresponding Research Paper)/2016/09/a-neural-network-for-machine.htmlhttps://arxiv.org/pdf/v2.pdfSecond blog post aboutZero-Shot Translations. This one made the biggest splash. (CorrespondingResearch Paper)/2016/11/zero-shot-translation-with-googles.htmlhttps://arxiv.org/pdf/v1.pdfA great NYTimes article thattells the story behind this Google Translate.//magazine/the-great-ai-awakening.html?_r=0本文作者 Sachin Joglekar 是 Google 的一位软件工程师,目前是一名爱好者。欢迎加入本站公开兴趣群商业智能与数据分析群兴趣范围包括各种让数据产生价值的办法,实际应用案例分享与讨论,分析工具,ETL工具,数据仓库,数据挖掘工具,报表系统等全方位知识QQ群:
上一篇:下一篇:}

我要回帖

更多关于 bp神经网络 图像识别 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信