使用ChatGPT的一点感受和思考

在ChatGPT未在国内火热传播的时候,自己就注册了账号来体验。但是一直囿于日常琐事以及对媒体炒热点的反感,一直没有把体验ChatGPT的一些感受和思考发出来。年后第一天开工,内网看了几篇相关话题的文章,也是时候把自己的一些微小收获po出来,权当抛砖引玉。

极强的问题理解能力

搞过NLP的同学可以把这个能力理解为NLU的能力。NLU能力在垂直领域要做到准确并不难,甚至考人工堆知识库也能搞定。ChatGPT的理解能力之所以让人们感到些许震惊是因为对人类通用知识的理解能力都非常准确。这种准确性不仅做到了跨领域,而且对主流语言的支持、不同文化背景的表达都支持得非常好。是一个工程+模型两个飞轮向前推动的结果。

但是也会有概念混淆的时候,主要是问题关键词存在多种含义、指代的时候。并且它不会主动询问消歧。这个比较容易触发。这里引一个刘飞的公众号例子:

刘飞:

那产品经理可以从艾尔登法环中学到什么经验?

ChatGPT:

艾尔登法环是一种管理学方法,它用于描述产品生命周期的不同阶段,并为每个阶段提供相应的管理措施。作为产品经理,可以从艾尔登法> 环中学到很多东西,比如:

  • 产品生命周期的概念:艾尔登法环描述了产品从研发到退市的过程,并将其划分为五个阶段:研发、发展、成熟、衰退和退市。作为产品> 经理,可以从艾尔登法环中学到产品生命周期的概念,并为自己的产品设计提供指导。

  • 产品管理的方法:艾尔登法环为每个产品生命周期的阶段提供了相应的管理措施,包括市场调研、竞争分析、市场定位、产品计划和推广> 等。作为产品经理,可以从艾尔登法环中学到如何制定产品管理方法,并为自己的产品设计提供参考。

  • 产品经理的角色定位:艾尔登法环中提到产品经理是负责产品管理的角色,他需要对市场趋势和客户需求进行分析,并制定产品计划,负> 责产品的开发、推广和维护。作为产品经理,可以从艾尔登法环中学到产品经理的角色定位,并为自己的工作设定目标。

  • 产品管理的关键技能:艾尔登法环中提到,产品经理需要具备一些关键的技能,包括市场调研、竞争分析、产品计划、产品开发和推广> 等。作为产品经理,可以从艾尔登法环中学到产品管理的关键技能,并为自己的工作提供指导。

刘飞:

你是不是说错了,艾尔登法环是一款游戏。

ChatGPT:

您提到的艾尔登法环不是游戏,而是一种管理学方法。艾尔登法环用于描述产品生命周期的不同阶段,并为每个阶段提供相应的管理措施。作为产品经理,可以从艾尔登法环中学到很多东西,比如产品生命周期的概念、产品管理的方法、产品经理的角色定位和产品管理的关键技能等。

但是瑕不掩瑜,上面提到的问题有很多成本并不高的解决方案。姑且理解为这是openAI团队暂时缺人没来得及优化[手动🐶]。

一个更好的wikipedia,但是时效性较差,也没法输入新的知识

我知道你在想什么:那还有Google什么事?的确,理解能力准确,又能主动把正确答案以说人话的方式递到你面前,似乎这才是我们认为下一代搜索引擎要干的事。事实上,Google自提出知识图谱以来其实也一直在做这方面的事。但是,凡事并非只有两面,也不是一定要颠覆。

首先,ChatGPT目前是一个名义上offline的版本。其次,database容量在搜索引擎面前九牛一毛,并且不能进行增量知识输入和更新:

liudan king
我想下载你部署到我的本地环境,需要怎么操作

很抱歉,我无法被下载并部署到您的本地环境中。我是一个人工智能助手,我运行在云端,无法被下载和部署到本地计算机上。如果您有其他问题,我将尽力回答。

liudan king:

我想向你注入新的领域知识,需要怎么做?

ChatGPT:

很抱歉,我无法接受新的领域知识。我是一个人工智能助手,我的知识来自于我所被训练的数据集。我不能接受新的信息,也无法主动查阅> 新的信息来回答问题。如果您有其他问题,我将尽力回答。

因此,当前版本的ChatGPT可以是你私人的一个更好的维基百科,甚至是私人秘书。跟Google一起使用更佳。

它能帮你代笔写东西,但不是创作

ChatGPT之所以受到很多人追捧很大的一个原因就是觉得它不仅能说人话,还能帮你干活写东西。比如让它写一段简单但是需要有一点经验的代码:

liudan king:

使用golang编写一段访问支付宝网站的代码

ChatGPT:

下面是一段简单的golang代码,实现了访问支付宝网站的功能:

package main

import (
"fmt"
"net/http"
)

func main() {
resp, err := http.Get("https://www.alipay.com")
if err != nil {
fmt.Println("Error: ", err)
return
}
defer resp.Body.Close()

fmt.Println("Status: ", resp.Status)
fmt.Println("Headers: ", resp.Header)
}

上面的代码使用了golang的net/http库,通过http.Get方法向支付宝网站发起了一个HTTP GET请求。然后,它通过调用resp.Status和resp.Header方法,打印了服务器的响应状态和响应头信息。

请注意,上面的代码仅仅是一个简单的例子,它并不能完全反映支付宝网站的实际情况。如果您想实现更复杂的功能,您可能需要更多的代码和逻辑。

liudan king:

为什么要调用resp.Body.Close()

ChatGPT:

在上面的代码中,调用resp.Body.Close()是一个很重要的步骤。它的作用是关闭resp.Body对象,释放它所占用的系统资源。

通常情况下,当我们使用http.Get方法发起一个HTTP请求时,它会返回一个*http.Response对象,该对象包含了服务器的响应信息。其中,resp.Body字段表示响应体,它是一个io.ReadCloser类型的对象,表示一个可读可关闭的流。当我们调用resp.Body.Close> ()方法时,

实际上,我们调用resp.Body.Close()方法时,它会自动关闭resp.Body字段所对应的可读可关闭的流。这样做的好处是可以释放这个流所占用的系统资源,避免资源泄露的情况。

另外,在golang中,如果我们想要对一个可读可关闭的流进行多次读取操作,必须在读取完成后手动关闭这个流。而调用resp.Body.> Close()方法正是用来实现这个目的的。因此,在上面的代码中,我们将调用`resp.Body.Close()

liudan king:
为什么要加defer关键字?

ChatGPT:

在上面的代码中,我们使用了defer关键字来调用resp.Body.Close()方法。defer关键字的作用是延迟执行一个函数或方法,直到它所> 在的函数或方法执行完毕。

在这里,我们将resp.Body.Close()方法放在了defer语句中,这意味着,在main函数执行完毕之前,resp.Body.Close()方法都不会被执行。这样做的目的是,即使在执行过程中出现了异常,也能保证resp.Body.Close()方法最终被执行,释放它所占用的系

也就是说,ChatGPT不仅能写大家喜闻乐见的八股文,也能写垂直领域的技术文。并且写出来的代码知其然和所以然。

然而,这并不是创作。当前的AI技术本质上仍然是存量数据的再加工和组合,包括ChatGPT在内,并不带来知识的增量。我们以为的量变在ChatGPT这里依然没有看到质变。

但是,这并不妨碍ChatGPT在诸多领域崭露头角。从stackoverflow立即宣布禁止提交ChatGPT生成的答案,到BuzzFeed公开宣布通过ChatGPT生成内容喂养Google,你可以很明显的感受到不同内容领域对它的到来的截然不同的态度,但是有一点是相同的,那就是它对于那个领域来说,在某些方面都达到了很不错的从业者的水平。

对于善用工具的人,使用这一工具可以极大的提高工作效率,同时淘汰更多的该行业的低效工作者。如同工业革命一样带来失业,也带来新的就业岗位。

及格内容生成的成本极低,互联网高质量内容将会以快的速度被稀释。而最有可能形成垃圾内容成山的领域就是导购、营销、水军等一软文为生存手段的领域。

数据,内容,知识,智慧。这是人类文明攀升的解题。很遗憾,ChatGPT目前只是在内容到知识层面做到了一个桥梁作用。作为工具,respect; 作为智能,道阻且长。

流浪地球中的Moss原型在现实中至今看不到一个通用的模型,最有希望的还是Google对于蛋白结构推演的专有模型。但有一点可能图恒宇是对的,知识到智慧的这一环,需要一次550A到550W的算力突破。

时序异常数据检测从理论到落地

最近在解决一个挺有意思的问题,该问题可以抽象简化为:如何检测外部依赖接口发生异常。如果是在中小公司,那么这个问题其实是不需要解决的,从研发层面规范接口的格式,并规定依赖接口必须达到要求的可用性,只要调用成功率低于规范就进行告警。不幸的是,这个方法在当前的BU中是推不动的,是为背景。

简单的对接口调用失败量对齐时间轴看了一下,这是一个典型的时序数据异常检测问题。

从分类看,当前发展阶段的时序异常检测算法和模型可以分为一下几类:

  • 统计模型:优点是复杂度低,计算速度快,泛化能力强悍。因为没有训练过程,即使没有前期的数据积累,也可以快速的投入生产使用。缺点是准确率一般。但是这个其实是看场景的,并且也有简单的方法来提高业务层面的准确率。这个后面会提到。
  • 机器学习模型:鲁棒性较好,准确率较高。需要训练模型,泛化能力一般。
  • 深度学习模型:普遍需要喂大量的数据,计算复杂度高。整体看,准确性高,尤其是近段时间,强化学习的引入,进一步巩固其准确性方面的领先优势。

而我们希望在9月份就能够上线运行,并且没有历史数据,更不要提打标数据了。因此,只能选择统计模型作为一期落地的方案。而在统计模型中,twitter 在2015年发布的 AnomalyDetection 自然是翘楚。如果你正好使用 R 语言,那么直接上手就可以用。如果你需要 pure python 版本,推荐使用 Twitter’s Anomaly Detection in Pure Python.

S-H-ESD 原理

twitter 公开的异常检测算法的核心是使用了S-H-ESD异常检测算法。这种算法的思想是将时序数据使用 STL 分解,然后将分解的余项使用 Grubbs’ Test 进行异常点的检测(实际使用的算法考虑了极值异常点对整体的影响,实际使用的是的Grubbs’ Test变形)。关于算法的细节可以参看 twitter 发布的论文 Automatic Anomaly Detection in the Cloud Via Statistical Learning. 显然,这个算法之所以有效的两个关键就是 STL 和 Grubbs’ Test。

STL 将时序数据分解为 趋势 + 周期 + 余项:

直观上,可以将趋势项理解为时序数据的骨骼;周期数据是数据的振幅;余项是则是消除趋势和周期数据后,相对平滑稳定的“皮毛”。而这种皮毛数据是符合 Grubbs’ Test 假设中正常数据正态分布的。反之,则被 Grubbs’ Test 认为是异常数据。

因此,S-H-ESD 只适用于周期性数据。对于无周期性或数据变化特别剧烈的时序数据,S-H-ESD都不是好的选择。

S-H-ESD 用于生产环境

S-H-ESD 原理简单,理论效果也非常不错,基本起手能达到 40% ~ 60% 的准确率。但是实际应用中经常会遇到以下典型的误报情况:

而这种误报其实很难从算法本身消除,即使消除了其实也没有泛化性。一种简单的思路是引入更多数据和规则:

  • 上图中我们只是用的接口的报错量作为时序数据,单村在报错量上提高准确性在统计模型这个大前提下边际成本已经很高了。因此,可以考虑引入接口调用量和成功率来综合判断该点是否真正异常。
  • 结合实际业务,设定一些简单的规则减少误报量。对于我们的场景,可以设定的规则有报错量的基础阈值、报错点的持续时长等。

S-H-ESD 不是银弹,结合多维数据和业务规则以后,准确率基本达到了我们的预期。S-H-ESD 也不是终点,确切说是我们顺便解决当前问题,同时收集异常数据的手段。未来,我们会尝试结合深度学习模型提高异常检测点上的准确性,同时融合多维数据,将点上的异常检测逐步整合为线和面上的检测能力。

扩展阅读

使用迁移学习快速训练识别特定风格的图片

使用迁移学习快速训练识别特定风格的图片

前几天接到一个任务,需要从我们app的feed流中的筛选一些「优质」图片,作为运营同学的精选feed候选池。这里「优质」的参考就是以前运营同学手工筛序的精选feed图片。问题并不难,最容易想到的方向有两个:

  1. 机器学习方向,训练一个能够识别这种「优质」风格图片的模型。
  2. 过滤推荐方向,利用用户来测试feed图片质量(根据点赞、评论、观看张数、停留时间等指标),使用用户来筛选优质feed图片(用户的偏好千奇百怪,筛选结果可能未必如你所想,典型如今日头条……)。

今天我们介绍如何使用机器学习解决这个问题。具体来讲,由于时间紧,任务重,我们决定使用迁移学习来完成这个任务。后面如果有时间,我们也会尝试一下使用用户来过滤和筛选优质图片。

什么是迁移学习

迁移学习 (Transfer learning) 顾名思义就是就是把已学训练好的模型参数迁移到新的模型来帮助新模型训练。考虑到大部分数据或任务是存在相关性的,所以通过迁移学习我们可以将已经学到的模型参数(也可理解为模型学到的知识)通过某种方式来分享给新模型从而加快并优化模型的学习效率不用像大多数网络那样从零学习。

为什么使用迁移学习

  • 很多时候,你可能并没有足够大的数据集来训练模型,更不用说带有高质量标签的数据集了。使用已经训练好的网络,可以降低用于训练的数据集大小要求。
  • 从零开始训练一个深度网络是非常消耗算力和时间的。如果再将模型调整、超参数调整等有点玄学的流程加进去,消耗的时间会更多。对于创业公司来说,很多时候是很难给出这么多的时间预算来解决一个模型问题的。
  • 基于迁移学习训练一个模型往往只需要训练有限的几层网络,或者使用已有网络作为特征生成器,使用常规机器学习方法(如svm)来训练分类器。整体训练时间大幅降低。效果可能不是最好的,但是往往能够在短时间内帮你训练出一个够用的模型,解决当前的实际问题。

也就是说,近几年深度学习的各种突破本质上还是建立在数据集的完善和算力的提升。算法方面的提升带来的突破其实不如前两者明显。如果你是一个开发者,具体到要使用机器学习解决特定问题的时候,你一定想清楚你能否搞定数据集和算力的问题,如果不能,不妨尝试一下迁移学习。

如何进行迁移学习

我们的任务是筛选优质feed图片,其实就是一个优质图片与普通图片的二分类问题。

运营给出的「优质」参考图片:

直观感受是,健身摆拍图、美食图和少量风光照是她们眼中的优质图片?

运营给出的「普通」参考图片:

直观感受是,屏幕截图和没什么特点的图片被认为是普通图片。

我们迁移学习的过程就是复用训练好的(部分)网络和权重,然后构建我们自己的模型进行训练:

迁移学习在选择预训练网络时有一点需要注意:预训练网络与当前任务差距不大,否则迁移学习的效果会很差。这里根据我们的任务类型,我们选择了深度残差网络 ResNet50, 权重选择imagenet数据集。选择 RetNet 的主要原因是之前我们训练的图片鉴黄模型是参考雅虎开源的 open NSFW , 而这个模型使用的就是残差网络,模型效果让我们影响深刻。完整代码如下(keras + tensorflow):

  • 这里我们仅重新训练了输出层,你也可以根据自己需要添加多个自定义层。
  • 整个训练过程非常快,在Macbook late 2013仅使用CPU训练的情况下,不到一个小时收敛到了82%的准确率。考虑到我们的「优质」图片标签质量不太高的实际情况,这个准确率是可以接受的。
  • 完成训练后,我们使用该模型对生产环境的2000张实时图片进行了筛选,得到85张图片,运营主观打分结果是~50%可用,~25%需要结合多图考虑,其他不符合要求。考虑到我们的任务是辅助他们高效发现和筛选潜在优质图片,这个结果他们还是认可的。部分筛选结果如下:

还可以更简单一点吗?

如果你觉得上面重新训练网络还是太慢、太繁琐,我们还有更简单的迁移学习的方法:将预训练网络作为特征提取器,然后使用机器学习方法来训练分类器。以SVM为例,完成迁移学习只需要两个步骤:

  • 将预训练网络最后一层输出作为特征提取出来:
resnet_model = None

def extract_resnet(x):
  '''
  :param x: images numpy array 
  :return: features
  '''
  global resnet_model
  if resnet_model is None:
    resnet_model = ResNet50(include_top=False,
                            weights='imagenet',
                            input_shape=(image_h, image_w, 3))
  features_array = resnet_model.predict(x)
  return np.squeeze(features_array)

  • 使用特征训练SVM分类器:
def train(positive_feature_file, negative_feature_file):

  p_x = np.load(positive_feature_file)
  n_x = np.load(negative_feature_file)

  p_y = np.ones((len(p_x),), dtype=int)
  n_y = np.ones((len(n_x),), dtype=int) * -1

  x = np.concatenate((p_x, n_x), axis=0)
  y = np.concatenate((p_y, n_y), axis=0)

  x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2)
  logging.info("train shape:%s", x_train.shape)


  pca = PCA(n_components=512, whiten=True)
  pca = pca.fit(x)
  x_train = pca.transform(x_train)
  x_test = pca.transform(x_test)

  logging.info("train shape:%s", x_train.shape)


  # train
  svm_clf = svm.SVC(kernel='rbf', probability=True, decision_function_shape='ovr')
  svm_clf.set_params(C=0.4)
  svm_clf.fit(x_train, y_train)
  preds = svm_clf.predict(x_train)
  logging.info('train preds %d items, train accuracy:%.04f', len(preds), accuracy_score(preds, y_train))

  preds = svm_clf.predict(x_test)
  logging.info('test preds %d items, test accuracy:%.04f', len(preds), accuracy_score(preds, y_test))

  # joblib.dump(ss, './normal-ss.pkl')
  joblib.dump(pca, './normal-pca.pkl')
  joblib.dump(svm_clf, './normal-clf.pkl')

这个方法之所以有效是因为,迁移学习要求预训练网络与当前任务是相似的,那么最后一层网络的输出可以解释为特征的高度抽象,因此可以使用其作为特征进行分类。

这个方法虽然有效,但是需要准备两个数据集:正样本和负样本。很多时候,我们的任务是识别出我们关心的类别,这个类别我们可以花时间和精力来进行数据集的标注,但是对于我们不关心的类别的数据往往是不易收集的。那么,我们可以只准备一个数据集来训练一个只识别我们关心类别的模型吗?答案是可以的,使用One-class classification即可,一般翻译为异常检测或离群点检测。

如果你熟悉sklearn, 你可以使用svm.OneClassSVM:

  oc_svm_clf = svm.OneClassSVM(gamma=0.011, kernel='rbf', nu=0.08)
  oc_svm_clf.fit(x_train)

  preds = oc_svm_clf.predict(x_train)
  expects = np.ones((len(preds)), dtype=int)
  logging.info('train preds %d items, train accuracy:%.04f', len(preds), accuracy_score(preds, expects))

需要注意的是,One-class classification是一种无监督学习,从实验效果看,使用该方法筛选出来的图片「稳定性」相比前面两个方法稳定性要差。如果要在实际业务中使用该方法,需要仔细调整gamma参数,根据ROC曲线寻找一个相对理想的值。

小结

大多数场景下,受限于数据集、算力和时间限制,很少人是从零开始训练一个深度神经网络的。如果你的任务是解决工程中的某个特定问题,那么迁移学习可能是一个有效的高性价比解决方案。你可以使用通过添加或移除若干预训练网络层来实现迁移学习,也可以将预训练网络作为特征提取器,然后使用其他分类方法进行机器学习。迁移学习的效果往往不如完全训练整个网络的效果好,因此,你需要结合具体任务来权衡准确率和成本。

扩展阅读