TowardsDataScience 2023 博客中文翻译(六十二)

原文:TowardsDataScience

协议:CC BY-NC-SA 4.0

从头开始构建树状 Parzen 估计器(有点像)

原文:towardsdatascience.com/building-a-tree-structured-parzen-estimator-from-scratch-kind-of-20ed31770478?source=collection_archive---------4-----------------------#2023-04-04

传统超参数调整方法的替代方案

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Colin Horgan

·

关注 发布于 Towards Data Science · 9 分钟阅读 · 2023 年 4 月 4 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2 维超参数调整的 TPE 可视化。图片由 Alexander Elvers via Wikipedia Commons 提供。

机器学习模型如何适应数据由一组称为超参数的初始条件决定。超参数有助于限制模型的学习行为,以便它(希望)能够很好地拟合数据并在合理的时间内完成。找到最佳的超参数集(通常称为“调优”)是建模任务中最重要且耗时的部分之一。历史上,超参数调优的方法涉及对超参数组合网格进行暴力搜索或随机搜索,分别称为网格搜索和随机搜索。尽管受欢迎,网格搜索和随机搜索方法缺乏收敛到一个合理的超参数集的方法——也就是说,它们完全是试错法。本文将探讨一种相对较新的超参数调优方法——树结构帕尔岑估计器(TPE)——并通过逐步实现的 Python 代码深入了解其功能。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1:网格搜索和随机搜索技术的动画。

TPE 是一种贝叶斯优化算法。这意味着它允许我们从一些关于最佳模型超参数的初始信念开始,并在学习不同超参数如何影响模型性能时,以有原则的方式更新这些信念。这已经比网格搜索和随机搜索有了显著的改进!我们可以通过尝试更多导致良好模型的超参数组合,而不是通过试错法来确定最佳超参数集。

TPE 得名于两个主要思想:1. 使用帕尔岑估计来建模我们对最佳超参数的信念(稍后会详细介绍)和 2. 使用一种称为后验推断图的树状数据结构来优化算法运行时间。在这个例子中,我们将忽略“树结构”部分,因为它与超参数调优本身无关。此外,我们不会深入讨论贝叶斯统计、期望改进等内容。这里的目标是对 TPE 及其工作原理有一个高层次的概念理解。有关这些主题的更深入讨论,请参阅 J. Bergstra 和同事关于 TPE 的原始论文 [1]

设置示例

为了构建我们的 TPE 实现,我们需要一个玩具示例来操作。假设我们想通过一些随机生成的数据找到最佳拟合线。在这个例子中,我们有两个超参数需要调优——线的斜率 m 和截距 b

import numpy as np

#Generate some data
np.random.seed(1)
x = np.linspace(0, 100, 1000)
m = np.random.randint(0, 100)
b = np.random.randint(-5000, 5000)
y = m*x + b + np.random.randn(1000)*700

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2:用于 TPE 的随机生成线性数据。

由于 TPE 是一种优化算法,我们还需要一些指标来优化。我们将使用均方根误差(RMSE)。让我们定义函数 rmse 来计算这个指标,如下所示:

def rmse(m, b):
    '''
    Consumes coeffiecients for our linear model and returns RMSE.

    m (float): line slope
    m (float): line intercept
    y (np.array): ground truth for model prediction
    '''
    preds = m*x + b
    return np.sqrt(((preds - y)**2).sum()/len(preds))

我们需要的最后一件事是一些关于最佳超参数的初步信念。假设我们认为最佳拟合线的斜率在 (10,100) 区间上是一个均匀随机变量,而截距也在 (-6000, -3000) 区间上是一个均匀随机变量。这些分布称为先验分布。它们是均匀随机变量等同于说我们认为最佳超参数的真实值在各自的区间内有相同的可能性。我们将实现一个类来封装这些变量,并使用它们来定义我们的初始搜索空间。

class UniformDist:
    '''
    Class encapsulates behavior for a uniform distribution.
    '''
    def __init__(self, min_, max_):
        '''
        Initializes our distribution with provided bounds
        '''
        self.min = min_
        self.max = max_

    def sample(self, n_samples):
        '''
        Returns samples from our distribution
        '''
        return np.random.uniform(self.min, self.max, n_samples)
#Define hyperparameter search space
search_space = {'m':UniformDist(10,100), 'b':UniformDist(-6000,-3000)}

完成所有这些设置后,我们可以继续编写算法本身。

步骤 1:随机探索

TPE 的第一步是从我们的先验分布中随机采样超参数集合。这个过程给了我们一个关于哪些搜索空间区域能够生成良好模型的初步估计。函数 sample_priors 消耗我们的初始搜索空间和要从中抽取的随机样本数。然后它使用我们的目标函数 rmse 评估生成的模型,并返回一个包含每次试验的斜率、截距和 RMSE 的 Pandas 数据框。

import pandas as pd

def sample_priors(space, n_samples):
    '''
    Consumes search space defined by priors and returns
    n_samples.
    '''
    seed = np.array([space[hp].sample(n_samples) for hp in space])

    #Calculate rmse for each slope intercept pair in the seed
    seed_rmse = np.array([rmse(m, b) for m, b in seed.T]) 

    #Concatenate and convert to dataframe
    data = np.stack([seed[0], seed[1], seed_rmse]).T
    trials = pd.DataFrame(data, columns=['m', 'b', 'rmse'])

    return trials

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3:30 次迭代的随机采样超参数结果。每个‘x’表示一个超参数样本。

步骤 2:划分搜索空间和 Parzen 估计

在从我们的先验分布生成一些初始样本后,我们现在使用分位数阈值 γ 将超参数搜索空间分成两个部分,其中 γ 在 0 和 1 之间。我们可以任意选择 γ=0.2。那些产生模型表现位于我们目前创建的所有模型的前 20% 的超参数组合被归入“良好”分布 l(x)。所有其他超参数组合则归入“差”分布 g(x)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 4:经过 30 轮随机选择超参数后的 l(x) 和 g(x) 分布的 KDE。颜色较深的区域表示密度较高。

结果表明,下一组要测试的最佳超参数组合由 g(x)/l(x) 的最大值给出(如果您想查看推导过程,请参见 [1])。这在直观上是合理的。我们希望超参数在我们的“好”分布 l(x) 下很可能,而在我们的“坏”分布 g(x) 下不太可能。我们可以使用 Parzen 估计器建模 g(x) 和 l(x),这就是“TPE”中的“PE”来自哪里。Parzen 估计的粗略思路即核密度估计(或 KDE)是我们将对一系列正态分布取平均,每个分布以属于 g(x) 或 l(x) 的观察值为中心。结果分布在我们的搜索空间中样本接近的区域具有高密度,而在样本远离的区域具有低密度。为了执行 Parzen 估计,我们将使用 SKLearn 库中的 KernelDensity 对象。函数 segment_distributions 消耗我们的试验数据框和我们的阈值 γ,并返回 l(x) 和 g(x) 的 Parzen 估计器。结果分布在图 4 中可视化。

from sklearn.neighbors import KernelDensity

def segment_distributions(trials, gamma):
    '''
    Splits samples into l(x) and g(x) distributions based on our
    quantile cutoff gamma (using rmse as criteria).

    Returns a kerned density estimator (KDE) for l(x) and g(x), 
    respectively.
    '''
    cut = np.quantile(trials['rmse'], gamma)

    l_x = trials[trials['rmse']<cut][['m','b']]
    g_x = trials[~trials.isin(l_x)][['m','b']].dropna()

    l_kde = KernelDensity(kernel='gaussian', bandwidth=5.0)
    g_kde = KernelDensity(kernel='gaussian', bandwidth=5.0)

    l_kde.fit(l_x)
    g_kde.fit(g_x)

    return l_kde, g_kde 

第 3 步:确定要测试的下一个“最佳”超参数

如第 2 步所述,下一组要测试的最佳超参数集最大化 g(x)/l(x)。我们可以通过以下方式确定这一组超参数。首先,我们从 l(x) 中抽取 N 个随机样本。然后,对于每一个样本,我们评估其相对于 l(x) 和 g(x) 的对数似然,选择最大化 g(x)/l(x) 的样本作为下一组要测试的超参数组合。我们决定使用的 SKLearn KernelDensity 实现使得这一计算非常简单。

def choose_next_hps(l_kde, g_kde, n_samples):
    '''
    Consumes KDE's for l(x) and g(x), samples n_samples from 
    l(x) and evaluates each sample with respect to g(x)/l(x).
    The sample which maximizes this quantity is returned as the
    next set of hyperparameters to test.
    '''
    samples = l_kde.sample(n_samples)

    l_score = l_kde.score_samples(samples)
    g_score = g_kde.score_samples(samples)

    hps = samples[np.argmax(g_score/l_score)]

    return hps

现在汇总

我们需要做的就是将之前讨论的所有组件串联起来,得到 TPE 的实现!我们需要做出的决定是我们想要进行多少轮随机探索,算法要完成多少次迭代,以及我们的截止阈值 γ 将是多少(是的,即使是 TPE 也有超参数)。在选择这些数量时,有几个方面需要考虑。

  1. 如果在开始 TPE 之前,您的先验没有捕捉到“最佳”超参数集,那么算法可能会很难收敛。

  2. 你进行的随机探索轮次越多,对 g(x) 和 l(x) 的初步近似就会越准确,这可能会改善tpe的结果。

  3. γ 的值越高,最终落在 l(x) 中的样本就会越少。仅有少量样本用于估计 l(x) 可能会导致 tpe 选择不佳的超参数。

def tpe(space, n_seed, n_total, gamma):
    '''
    Consumes a hyperparameter search space, number of iterations for seeding
    and total number of iterations and performs Bayesian Optimization. TPE
    can be sensitive to choice of quantile cutoff, which we control with gamma.
    '''

    #Seed priors
    trials = sample_priors(space, n_seed)

    for i in range(n_seed, n_total):

        #Segment trials into l and g distributions
        l_kde, g_kde = segment_distributions(trials, gamma)

        #Determine next pair of hyperparameters to test
        hps = choose_next_hps(l_kde, g_kde, 100)

        #Evaluate with rmse and add to trials
        result = np.concatenate([hps, [rmse(hps[0], hps[1])]])

        trials = trials.append(
            {col:result[i] for i, col in enumerate(trials.columns)},
            ignore_index=True
        )

    return trials

结果

要对我们之前创建的合成数据执行 TPE,我们运行如下:

#Define hyperparameter search space
np.random.seed(1)
search_space = {'m':UniformDist(10,100), 'b':UniformDist(-6000,-3000)}

df = tpe(search_space, 
         n_seed=30, 
         n_total=200, 
         gamma=.2)

就这些!我们现在可以分析我们的结果。为了简洁起见,生成以下可视化所用的代码将不予展示。然而,源代码可以在此项目的 GitHub 仓库中找到。

首先,让我们将 TPE 的最佳超参数设置与回归求解器得到的实际最佳斜率和截距进行比较。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5:使用 TPE 和线性回归获得的超参数的最佳拟合线。

从图 5 中可以看出,使用 TPE 我们能够密切接近我们线性回归模型的最佳超参数设置。我们不期望 TPE 能超越回归求解器,因为线性回归有一个封闭形式的解。然而,在无限次的试验中,我们期望它会收敛到类似的解。

TPE 是一种优化算法,因此我们不仅关心是否能够找到一组不错的超参数。我们还需要检查在 200 次迭代中我们的目标函数是否降低。图 6 展示了在初始 30 个随机样本之后,我们的 TPE 实现有一个明确的(或大致上)趋势来最小化我们的目标函数。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 6:所有 TPE 试验中的 RMSE。注意左侧和右侧图中 y 轴刻度的差异。红点表示具有最低 RMSE 的试验。

到目前为止一切看起来都很棒!我们最后要检查的是我们关于超参数“最佳”分布的信念在 200 次迭代中的变化。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 7:我们 TPE 算法在 200 次迭代中的 l(x)的 Parzen 估计。

如图 7 所示,我们从一个非常宽泛的 l(x)分布开始,迅速收敛到接近最终结果的分布。图 6 和图 7 清楚地说明了 TPE 的三个简单步骤如何组合成一个能够以复杂但直观的方式探索搜索空间的算法。

结论

超参数调优是建模过程中的关键部分。尽管网格搜索和随机搜索方法易于实现,但 TPE 作为替代方案提供了一个更有原则的超参数调优方法,从概念上也比较简单。许多 Python 库都很好的实现了 TPE,包括Hyperopt(由[1]的作者创建并维护)和Optuna。无论是像我们的玩具示例一样简单,还是像神经网络超参数调优一样复杂,TPE 都是一个多功能、有效且简单的技术,近年来在数据科学和机器学习领域越来越受欢迎。下次当你在调整模型超参数时,或许可以跳过网格搜索。

参考文献

  1. Bergstra, J., Bardenet, R., Bengio, Y., & Kégl, B., 超参数优化算法 (2011),神经信息处理系统进展24

除非另有说明,否则所有图像均由作者提供。

用整体思维模型构建 AI 产品

原文:towardsdatascience.com/building-ai-products-with-a-holistic-mental-model-33f8729e3ad9?source=collection_archive---------2-----------------------#2023-09-03

一个由跨学科团队进行 AI 产品构思、规划和定义的工具

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Dr. Janna Lipenkova

·

关注 发表在 数据科学前沿 · 23 分钟阅读 · 2023 年 9 月 3 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

注:本文是名为“剖析 AI 应用”的系列文章中的第一篇,介绍了 AI 系统的心理模型。该模型作为跨学科 AI 和产品团队讨论、规划和定义 AI 产品的工具,以及与业务部门对齐的工具,旨在汇集产品经理、用户体验设计师、数据科学家、工程师和其他团队成员的观点。在本文中,我介绍了心理模型。后续文章将展示如何将其应用于特定的 AI 产品和功能:

  • 通过对话访问数据创建信息优势

  • 通过大型语言模型重新定义对话 AI

我将在未来的文章中分析一系列其他 AI 应用,并且也在准备我的书 创建智能产品 ,该书专为产品构建者介绍 AI。关注我,保持最新动态!

公司常常认为,将 AI 纳入其产品中只需聘请 AI 专家,让他们施展技术魔法即可。这种方法直接导致了集成谬误:即便这些专家和工程师生产出卓越的模型和算法,它们的输出往往停留在游乐场、沙箱和演示阶段,永远无法真正成为产品的完整组成部分。多年来,我见证了许多数据科学家和工程师的挫败感,他们的技术出色的 AI 实现并未成为用户面对的产品。相反,它们被赋予了前沿实验的光荣地位,使内部利益相关者产生了骑乘 AI 浪潮的印象。现在,自从 2022 年 ChatGPT 发布以来,AI 的普及无处不在,公司再也无法将 AI 作为展示其技术水平的“灯塔”功能。

为什么集成 AI 如此困难?原因有几个:

  • 团队常常专注于 AI 系统的单一方面。这甚至导致了数据中心、模型中心和人机中心等不同阵营的出现。虽然每个阵营都为研究提供了激动人心的视角,但实际产品需要将数据、模型和人机交互结合成一个连贯的系统。

  • AI 开发是一个高度协作的企业。在传统的软件开发中,你面对的是后端和前端组件的相对清晰的二分法。在 AI 中,你不仅需要为你的团队增加更多的角色和技能,还需要确保不同方之间的紧密合作。你的 AI 系统的不同组件将以紧密的方式相互作用。例如,如果你正在开发一个虚拟助手,你的用户体验设计师必须了解提示工程以创建自然的用户流程。你的数据标注员需要了解你的品牌和虚拟助手的“性格特征”,以创建一致且符合你定位的训练数据,而你的产品经理需要掌握并审视数据管道的架构,以确保它符合用户的治理关注。

  • 在构建 AI 时,公司经常低估设计的重要性。虽然 AI 从后端开始,但良好的设计对于在生产中展现其价值是不可或缺的。AI 设计突破了传统 UX 的界限。你提供的大部分功能在界面上并不直接可见,而是“隐藏”在模型中,你需要教育和引导用户以最大化这些好处。此外,现代基础模型可能会产生有毒、错误和有害的输出,因此你需要设置额外的保护措施来减少这些风险。所有这些可能需要你团队掌握新的技能,如提示工程和对话设计。有时,这也意味着做一些违反直觉的事情,比如低估价值以管理用户期望,以及增加摩擦以赋予用户更多控制和透明度。

  • AI 热潮带来了压力。许多公司在没有经过客户和市场需求验证的情况下急于实施。偶尔提及 AI 热词可以帮助你在市场上定位自己为一个进步和创新的企业,但从长远来看,你需要通过真正的机会来支撑你的热词和实验。这可以通过业务和技术之间的紧密协调来实现,基于市场机会和技术潜力的明确映射。

在这篇文章中,我们将构建一个集成了这些不同方面的 AI 系统的思维模型(参见图 1)。它鼓励构建者从整体上进行思考,清晰理解他们的目标产品,并在过程中根据新的见解和输入进行更新。该模型可以作为一种工具来简化协作,协调 AI 团队内外的多样化视角,并基于共同愿景构建成功的产品。它不仅适用于新的 AI 驱动的产品,也适用于整合到现有产品中的 AI 功能。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1:AI 系统的思维模型

以下部分将简要描述每个组件,重点关注那些特定于人工智能产品的部分。我们将从商业视角开始——市场机会和价值——然后深入探讨用户体验和技术。为了说明这一模型,我们将使用生成营销内容的副驾驶作为例子。

1. 机会

随着你现在可以用人工智能做的所有酷炫事情,你可能迫不及待地想动手开始构建。然而,为了构建出用户需要和喜爱的东西,你应该以市场机会为基础来支持你的开发。在理想的情况下,机会来自于客户告知我们他们需要或想要什么。[1] 这些可以是未满足的需求、痛点或愿望。你可以在现有的客户反馈中寻找这些信息,例如产品评论和销售及成功团队的笔记。此外,不要忘记你自己也可能是你产品的潜在用户——如果你正在解决一个你自己经历过的问题,这种信息优势就是额外的优势。除此之外,你还可以使用调查和访谈等工具进行主动的客户研究。

比如,我不需要看得太远就能看到创业公司以及大型公司在内容营销方面的痛苦。我自己也经历过——随着竞争的加剧,通过个体、定期且(!)高质量的内容来建立思想领导力变得越来越重要,以便于区分。而且,对于一个小而忙碌的团队来说,总会有比写一周博客帖子更重要的事情。同时,我也经常遇到我网络中的人,他们在建立一致的内容营销常规方面苦苦挣扎。这些“本地”的、可能有偏见的观察可以通过超出个人网络的调查来验证,从而确认解决方案的更广泛市场。

现实世界略显模糊,客户并不会总是主动向你提出新的、精心构思的机会。相反,如果你张开你的天线,机会将从多个方向向你靠近,例如:

  • 市场定位:人工智能很时髦——对于已经建立的企业,它可以用来增强企业作为创新、高科技、未来-proof 等的形象。例如,它可以将现有的营销公司提升为一个人工智能驱动的服务,并使其与竞争对手区分开来。然而,不要为了人工智能而做人工智能。市场定位的技巧需要谨慎应用,并与其他机会结合使用——否则,你有失去信誉的风险。

  • 竞争对手:当你的竞争对手采取行动时,他们可能已经完成了基础研究和验证。过一段时间看看他们——他们的发展是否成功?利用这些信息来优化你自己的解决方案,采纳成功的部分,纠正错误。例如,假设你观察到一个竞争对手提供完全自动化生成营销内容的服务。用户点击一个“大红按钮”,AI 就会继续撰写和发布内容。经过一些研究,你了解到用户犹豫使用这个产品,因为他们希望对过程保持更多的控制,并将自己的专业知识和个性融入写作中。毕竟,写作也涉及自我表达和个体创造力。这是你前进的时机,推出一个功能丰富、可配置的多功能工具,让用户能够在需要时将自己融入到内容创建过程中。

  • 法规:技术颠覆和全球化等宏观趋势迫使监管者收紧要求。法规带来压力,并且是防弹的机会来源。例如,假设有一项法规要求每个人都必须明确标识 AI 生成的内容。那些已经使用 AI 内容生成工具的公司将会消失于内部讨论中,考虑是否接受这一要求。许多公司会因为想要保持真实的思想领导形象而选择回避,而不是生产明显的 AI 生成的模板。假设你聪明地选择了一个增强型解决方案,让用户有足够的控制权,从而能够保持文本的正式“作者”身份。当新的限制被引入时,你是免疫的,可以迅速前进以利用这一法规,而那些使用完全自动化解决方案的竞争对手则需要时间来恢复。

  • 使能技术:新兴技术和现有技术的重大突破,例如 2022–23 年的生成式 AI 浪潮,可以开辟新的做事方式,或将现有应用提升到一个新水平。假设你过去十年一直经营一家传统的营销公司。现在,你可以开始将 AI 技巧和解决方案引入你的业务,提高员工的效率,利用现有资源服务更多客户,并增加利润。你是在现有专业知识、声誉和(希望是良好意图的)客户基础的基础上进行的,因此引入 AI 增强功能可能比新进入者要顺利和风险更小。

最后,在现代产品世界中,机会往往不那么明确和正式,可以通过实验直接验证,从而加快你的开发。因此,在以产品驱动的增长中,团队成员可以提出自己的假设,而不必严格依赖数据驱动的论证。这些假设可以以逐步的方式制定,例如修改提示或更改一些 UX 元素的本地布局,这使得它们易于实施、部署和测试。通过消除对每个新建议提供先验数据的压力,这种方法利用了所有团队成员的直觉和想象力,同时强化了对建议的直接验证。假设你的内容生成运行顺利,但你听到越来越多关于 AI 透明性和可解释性不足的投诉。你决定实施额外的透明度级别,并向用户展示用于生成内容的具体文档。你的团队对一组用户进行了功能测试,发现他们很高兴使用该功能来追溯原始信息来源。因此,你决定将其建立在核心产品中,以提高使用率和满意度。

2. 价值

要理解和传达你 AI 产品或功能的价值,你首先需要将其映射到一个用例——它将解决的具体业务问题——并找出 ROI(投资回报率)。这迫使你将思维从技术层面转移到解决方案的用户侧利益上。ROI 可以沿着不同的维度进行衡量。对于 AI,一些维度包括:

  • 提高效率:AI 可以成为个人、团队和整个公司生产力的助推器。例如,对于内容生成,你可能会发现,现在你可以在 1-2 小时内完成原本需要 4-5 小时的博客文章[2],并将节省下来的时间用于其他任务。效率的提升通常伴随着成本的节约,因为完成相同工作所需的人力减少。因此,在商业环境中,这种好处对用户和领导层都很有吸引力。

  • 更个性化的体验:例如,你的内容生成工具可以让用户设置他们公司的一些参数,如品牌属性、术语、产品优势等。此外,它还可以跟踪特定作者的编辑内容,并随着时间的推移,将其生成适应该用户独特的写作风格。

  • 趣味和愉悦:在这里,我们探讨了产品使用的情感层面,也就是 Don Norman 所称的“本能”层面。像游戏和增强现实这样的产品在 B2C 领域存在着整个类别。那么 B2B 呢——你不会认为 B2B 产品存在于一个无菌的专业真空中?实际上,这个类别可以产生比 B2C 更强烈的情感反应。例如,写作可以被视为一种令人满意的自我表达行为,或者作为与写作障碍和其他问题的内在斗争。考虑一下你的产品如何增强任务的积极情感,同时缓解甚至转化其痛苦的方面。

  • 便利性:你的用户需要做什么才能利用 AI 的魔力?设想将你的内容生成助手集成到流行的协作工具中,如 MS Office、Google Docs 和 Notion。用户将能够在不离开其数字“家”的舒适环境下访问你产品的智能和效率。因此,你最小化了用户体验产品价值和持续使用的努力,从而提升了用户获取和采纳率。

一些 AI 的好处——例如效率——可以直接量化 ROI。对于像便利性和愉悦感这样不那么具体的收益,你需要考虑代理指标,如用户满意度。记住,从终端用户价值的角度思考,不仅能缩小用户与产品之间的差距。作为一种意外的副作用,它可以减少你公共沟通中的技术细节。这将防止你无意中吸引不必要的竞争。

最后,你应该尽早考虑的一个基本价值方面是可持续性。你的解决方案如何影响社会和环境?在我们的例子中,自动化或增强的内容生成可能会取代和消除大规模的人类工作负荷。你可能不希望被称为某个整个职业类别的“杀手”——毕竟,这不仅会引发伦理问题,还会招致威胁你工作的用户的抵制。考虑一下你如何解决这些担忧。例如,你可以教育用户如何有效利用他们的新空闲时间来设计更复杂的营销策略。这些可以为你提供一个可防御的护城河,即使其他竞争者赶上了自动化内容生成。

3. 数据

对于任何类型的 AI 和机器学习,你需要收集和准备数据,以使其反映现实生活中的输入,并为你的模型提供足够的学习信号。如今,我们看到一种数据中心 AI 的趋势——这种 AI 方法远离对模型的无休止调试和优化,专注于修复输入到这些模型中的数据中的众多问题。当你开始时,有不同的方法可以获得一个合适的数据集:

  • 你可以使用现有的数据集。这可以是标准的机器学习数据集,也可以是具有不同初始目的的数据集,经过适配以适合你的任务。有一些数据集经典,例如用于情感分析的IMDB 电影评论数据集和用于手写字符识别的MNIST 数据集。还有更多异国情调和令人兴奋的替代方案,如Catching Illegal FishingDog Breed Identification,以及 Kaggle 等数据中心的无数用户策划的数据集。找到一个专门为你的特定任务而制作且完全满足你需求的数据集的机会相当小,在大多数情况下,你还需要使用其他方法来丰富你的数据。

  • 你可以手动注释或创建数据以产生正确的学习信号。手动数据注释——例如,对文本进行情感评分——曾是早期机器学习中的常用方法。最近,它作为 ChatGPT 秘密武器的主要成分重新引起了关注。大量的人工努力被投入到创建和排序模型的响应,以反映人类的偏好。这种技术也被称为从人类反馈中进行强化学习(RLHF)。如果你拥有必要的资源,可以用它们来创建高质量的数据,以应对更具体的任务,比如生成营销内容。注释可以在内部完成,也可以使用外部供应商或诸如 Amazon Mechanical Turk 这样的众包服务。无论如何,大多数公司都不愿意花费大量资源进行 RLHF 数据的手动创建,并且会考虑一些自动化数据创建的技巧。

  • 因此,你可以使用数据增强来向现有的数据集添加更多示例。对于情感分析等简单任务,你可以在文本中引入一些额外的噪声,改变几个词汇等。对于更开放的生成任务,目前对使用大型模型(例如基础模型)进行自动化训练数据生成充满热情。一旦你确定了增强数据的最佳方法,就可以轻松地将其扩展到所需的数据集大小。

在创建数据时,你面临质量和数量之间的权衡。你可以手动标注较少的数据,保证其高质量,或者将预算花在开发自动数据增强的黑客技术和窍门上,这会引入额外的噪声。如果你选择手动标注,可以在内部进行,并形成注重细节和质量的文化,或者将工作众包给匿名人员。众包通常质量较低,因此你可能需要标注更多数据以补偿噪声。如何找到理想的平衡?这里没有现成的解决方案——最终,你将通过不断的训练和数据增强来找到理想的数据组成。一般来说,在预训练模型时,它需要从头开始获取知识,这只能通过大量数据来实现。另一方面,如果你想对一个已经存在的大模型进行微调并进行最后的专业化处理,你可能会更重视质量而非数量。在这种情况下,使用详细指南对小数据集进行受控手动标注可能是最佳解决方案。

最终,你可以获得的最有价值的数据来自生产。当你的应用上线时,你应该设置数据收集机制,以收集用户输入、AI 输出,以及(如果可能的话)额外的学习信号,如用户评估。这将创造数据网络效应,其中单个用户从你模型的大规模集体学习中受益。具体来说,重用生产数据进行微调将使你的模型尽可能接近用户期望的“真实情况”。这会导致更高的用户满意度、更频繁的使用和参与,从而获得更多高质量的数据——这是一个被称为“数据飞轮”的良性循环。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2:数据飞轮

4. 智能

数据是你的模型将学习的原材料,希望你能编制一个有代表性、高质量的数据集。现在,你的 AI 系统的实际智能——其从现有数据中学习并推广到新数据的能力——存在于机器学习算法和模型中,以及这些算法和模型可以调用的任何附加工具和插件中。在核心 AI 模型方面,你可以使用三种主要选项:

  • 提示现有模型。 GPT 系列的高级大语言模型(如 ChatGPT 和 GPT-4),以及来自 Anthropic 和 AI21 Labs 等其他提供商的模型,都可以通过 API 进行推理。通过提示,你可以直接与这些模型对话,在提示中包含完成任务所需的所有领域和任务特定的信息。这可以包括要使用的具体内容、类似任务的示例(少量示例提示)以及模型需要遵循的指令。例如,如果你的用户想生成一篇关于新产品特性的博客文章,你可以要求他们提供一些关于该特性的核心信息,如其优点和用例、使用方法、发布日期等。然后,你的产品将这些信息填入精心设计的提示模板中,并要求 LLM 生成文本。提示非常适合快速启动预训练模型。然而,随着时间的推移,通过提示构建的护城河会迅速变薄——在中期,你需要一个更具防御性的模型策略来维持你的竞争优势。

  • 微调预训练模型。 这种方法使 AI 在过去几年中变得非常受欢迎。随着越来越多的预训练模型的出现,以及 Huggingface 等门户提供模型仓库和标准代码来处理这些模型,微调正在成为尝试和实施的首选方法。当你使用预训练模型时,你可以从别人已经在模型的数据、训练和评估上所做的投资中受益,这些模型已经“了解”了很多关于语言和世界的知识。你只需使用任务特定的数据集对模型进行微调,这个数据集可以远小于最初用于预训练的数据集。例如,对于营销内容生成,你可以收集一组在参与度方面表现良好的博客文章,并对这些文章的指令进行逆向工程。从这些数据中,你的模型将学习成功文章的结构、流程和风格。微调是在使用开源模型时的最佳选择,但像 OpenAI 和 Cohere 这样的 LLM API 提供商也越来越多地提供微调功能。特别是在开源轨道上,你仍需考虑模型选择、训练和部署较大模型的成本开销,以及模型的维护和更新计划。

  • 从零开始训练你的机器学习模型。 一般来说,这种方法适用于较简单但高度特定的问题,对于这些问题,你有特定的知识或合适的数据集。内容生成不完全符合这一类别——它需要高级语言能力来起步,这些能力只能在经过大量数据的训练后获得。较简单的问题,如特定类型文本的情感分析,通常可以用像逻辑回归这样的既有机器学习方法来解决,这些方法的计算成本低于复杂的深度学习方法。当然,也存在诸如特定领域的概念提取这样的适度复杂问题,你可能会考虑从头训练一个深度神经网络。

除了训练之外,评估对于成功使用机器学习至关重要。合适的评估指标和方法不仅对 AI 功能的自信发布很重要,而且将作为进一步优化的明确目标,并作为内部讨论和决策的共同基础。虽然技术指标如精确度、召回率和准确率可以提供一个良好的起点,但最终,你会想寻找反映 AI 为用户提供的实际价值的指标。

5. 用户体验

AI 产品的用户体验是一个引人入胜的主题——毕竟,用户对与 AI“合作”寄予了很高的期望,但也有对 AI 超越并可能超越他们智能的担忧。这种人机合作的设计需要一个深思熟虑且明智的发现和设计过程。一个关键的考虑因素是你希望你的产品提供多少自动化——请注意,完全自动化远不是理想解决方案。以下图示展示了自动化的连续体:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3:AI 系统的自动化连续体

让我们来看一下这些层级:

  • 在第一个阶段,人类做所有的工作,且没有自动化。尽管对 AI 的炒作很多,但现代公司中大多数知识密集型任务仍在这一层面进行,这为自动化提供了巨大的机会。例如,那个抵制 AI 驱动工具并坚信写作是一项高度手动且特有的工艺的内容撰写者就在这里工作。

  • 辅助人工智能的第二阶段,用户对任务执行拥有完全的控制权,并且大部分工作是手动完成的,但 AI 工具帮助他们节省时间并弥补不足之处。例如,当在紧迫的截止日期内撰写博客文章时,使用 Grammarly 或类似工具进行最终语言检查可以成为一个受欢迎的节省时间的方法。它可以消除手动修订,这需要大量宝贵的时间和注意力,且可能仍然存在错误和遗漏——毕竟,人非圣贤。

  • 增强智能是指人工智能作为一个合作伙伴,增强人类的智能,从而利用两个世界的优势。与辅助人工智能相比,机器在您的过程中可以说更多,涵盖更多的责任,例如构思、生成和编辑草稿,以及最终的语言检查。用户仍需参与工作,做出决策,并完成部分任务。用户界面应清楚地指示人类和人工智能之间的劳动分配,突出错误潜在性,并提供对其执行步骤的透明度。简而言之,“增强”体验通过迭代和精炼引导用户达到期望的结果。

  • 最后,我们有完全自动化——这是对人工智能爱好者、哲学家和专家来说的一个有趣想法,但通常不是现实产品的最佳选择。完全自动化意味着您提供一个“红色大按钮”,启动过程并将完全控制交给机器。一旦人工智能完成,用户将面对最终输出,要么接受,要么放弃。中间发生的任何事情他们无法影响。完全自动化是设计方法的重要元素,如环境智能和冷静技术,应用于智能家电、语音助手等。然而,目前,LLM 和其他基础模型远未能捕捉和处理它们需要的丰富上下文信息,以实现无缝和可靠的自动化操作。可以想象,完全自动化的用户体验选项相当有限,因为几乎没有互动。成功的主要责任落在您的技术同事肩上,他们需要确保输出质量异常高。

AI 产品在设计时需要特殊对待。标准的图形界面是确定性的,允许你预见用户可能采取的所有路径。相比之下,大型 AI 模型是概率性的和不确定的——它们展示了一系列惊人的能力,但也存在诸如有毒、错误和有害输出的风险。从外部来看,你的 AI 界面可能看起来很简单,因为产品的大部分能力存在于模型中,并且对用户不可直接见到。例如,一个 LLM 可以解释提示、生成文本、搜索信息、总结内容、采用特定的风格和术语、执行指令等。即使你的 UI 是一个简单的聊天或提示界面,也不要让这种潜力被忽视——为了引导用户成功,你需要明确和现实。让用户了解你的 AI 模型的能力和局限性,允许他们轻松发现和修正 AI 犯的错误,并教会他们迭代自己以获得最佳输出的方法。通过强调信任、透明度和用户教育,你可以让你的用户与 AI 进行合作。虽然深入探讨 AI 设计这一新兴学科超出了本文的范围,但我强烈建议你从其他 AI 公司以及设计的其他领域,如人机交互,寻找灵感。你将很快识别出一系列重复的设计模式,如自动补全、提示建议和 AI 通知,这些都可以整合到你的界面中,以充分利用你的数据和模型。

此外,为了提供一个真正出色的设计,你可能需要为你的团队添加新的设计技能。例如,如果你正在构建一个用于优化营销内容的聊天应用程序,你将需要与负责对话流程和聊天机器人“个性”的对话设计师合作。如果你正在开发一个需要彻底教育和引导用户通过各种选项的增强型产品,一个内容设计师可以帮助你建立合适的信息架构,并为你的用户添加适当的引导和提示。

最后,对意外保持开放态度。AI 设计可能会让你重新思考关于用户体验的原始观念。例如,许多 UX 设计师和产品经理被训练去最小化延迟和摩擦,以平滑用户体验。然而,在 AI 产品中,你可以暂停这种斗争,利用这两者的优势。延迟和等待时间对于教育用户非常有用,例如通过解释 AI 当前正在做什么以及指示他们可能的下一步。中断,例如对话和通知弹窗,可以引入摩擦,以加强人机合作关系,并增加用户的透明度和控制感。

6. 非功能需求

除了数据、算法和用户体验(UX)之外,还需要考虑所谓的非功能需求(NFRs),如准确性、延迟、可扩展性、可靠性和数据治理,这些都确保用户确实能够获得预期的价值。NFRs 的概念源自软件开发,但在人工智能领域尚未得到系统性考虑。这些需求通常是在用户研究、构思、开发和人工智能能力运营过程中,随时出现时才会被采纳。

你应该尽早理解和定义你的非功能需求,因为不同的非功能需求将在你旅程的不同阶段显现。例如,隐私需要从数据选择的初始步骤开始考虑。准确性在生产阶段最为敏感,当用户开始在线使用你的系统时,可能会用意外的输入使系统不堪重负。可扩展性是一个战略考虑因素,当你的业务扩大用户和/或请求数量或提供的功能范围时,这一考虑因素会变得重要。

在非功能需求方面,你不可能全部满足。以下是一些你需要平衡的典型权衡:

  • 提高准确性的首要方法之一是使用更大的模型,这会影响延迟。

  • 使用“原样”的生产数据进行进一步优化可能对学习最有利,但可能会违反你的隐私和匿名规则。

  • 更具可扩展性的模型是通用型的,这会影响它们在公司或用户特定任务上的准确性。

如何优先考虑不同的需求将取决于可用的计算资源、你的用户体验概念(包括自动化的程度)以及由人工智能支持的决策的影响。

关键要点

  1. 从结果倒推:不要假设技术本身就能完成任务;你需要一个明确的路线图来将人工智能集成到面向用户的产品中,并教育用户了解其优点、风险和局限性。

  2. 市场对齐:优先考虑市场机会和客户需求来指导人工智能的发展。不要因为炒作而急于实施人工智能,尤其是在没有市场验证的情况下。

  3. 用户价值:定义、量化并传达人工智能产品在效率、个性化、便利性及其他价值维度方面的价值。

  4. 数据质量:专注于数据质量和相关性,以有效地训练人工智能模型。尝试使用小规模、高质量的数据进行微调,而使用较大的数据集进行从头训练。

  5. 启动数据飞轮:你最有价值的数据来自生产。确保你有机制记录这些数据,并通过用户反馈等额外学习信号来丰富数据。

  6. 智能性:为你的用例选择合适的复杂性和防御性(提示、微调、从零开始训练),并仔细评估其性能。随着时间的推移,你将获得更多的专业知识和信心,并可以考虑切换到更高级的模型策略。

  7. 以用户为中心的设计:在设计 AI 产品时要考虑用户需求和情感,平衡自动化与用户控制。注意概率 AI 模型的“不可预测性”,并引导用户与之协作并从中受益。

  8. 人类与 AI 伙伴关系的深思熟虑设计:通过强调信任、透明度和用户教育,你可以让用户与 AI 进行协作。

  9. 非功能性需求:在开发过程中考虑准确性、延迟、可扩展性和可靠性等因素,并尽早评估这些因素之间的权衡。

  10. 协作:促进 AI 专家、设计师、产品经理和其他团队成员之间的密切合作,以利用跨学科的智慧,成功整合你的 AI。

参考文献

[1] Teresa Torres (2021). 《持续发现习惯:发现创造客户价值和商业价值的产品》。

[2] Orbit Media (2022). 《新的博客统计数据:2022 年什么内容策略有效?我们采访了 1016 位博客作者》

[3] Don Norman (2013). 《日常物品的设计》。

[4] Google, Gartner and Motista (2013). 《从推广到情感:将 B2B 客户与品牌连接起来》

注:所有图片均由作者提供。

为企业构建人工智能战略

原文:towardsdatascience.com/building-ai-strategies-for-businesses-7b2e900399b7

通过沃德利地图制定人工智能战略的艺术

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 John Adeojo

·发表于Towards Data Science ·阅读时间 13 分钟·2023 年 6 月 6 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由作者提供:通过 Midjourney 生成

背景——在一家成熟银行主导人工智能战略

在创办 Data-Centric Solutions 之前,我负责了一家成熟银行的人工智能战略的开发、执行和实施。尽管在这种规模的交付上相对较为青涩,但我还是充满热情地接受了这份工作。消除了最初的冒名顶替综合症,我安慰自己,即使最坏的情况也不过是犯几个错误、吸取教训并实现专业成长。

人工智能战略显然比我最初认为的要复杂得多。在我的职业生涯中,我有幸参与了成功和不成功的战略。我希望分享一些我获得的宝贵见解,并希望这能为他人提供一个基础。

灵感来源于沃德利地图

我最初是通过一位值得信赖的导师推荐发现了沃德利地图的。对于那些不熟悉的人,沃德利地图是一种系统映射的方法。顾名思义,这种方法是由西蒙·沃德利开发的。

起初,我有些怀疑,但随着深入了解,我越来越认识到它的价值。我发现这些不仅是阐述战略的绝佳方式,而且是不可或缺的工具。

让我信服的是沃德利的棋类比喻。作为一个狂热的国际象棋爱好者,我在能抽出时间时都会下棋,这个比喻让我深感触动。国际象棋虽然比商业简单得多,但仍是一种战略游戏。沃德利强调,能够在国际象棋中制定和实施战略是因为存在一张地图,即棋盘本身!

如果你愿意,你可以阅读 Wardley 的 国际象棋类比,像我一样,你可能会被说服去追求这种方法!

什么构成了一个图?

根据 Wardley,以下六个组件对于任何图来说都是有用的:

  1. 图是可视化的,这在棋盘上无可否认。

  2. 图是上下文的。我们承认棋盘与国际象棋游戏有关。

  3. 图使位置的理解成为可能。我们安排棋盘,以便理解棋子的摆放。

  4. 参考一个锚点。锚点是板上固有的,根据板在玩家和棋子之间的位置为我们提供方向感。

  5. 图允许运动的理解。棋盘的设计模式让我们理解运动。

  6. 图包含组件。在棋类比中,棋子就是组件。

理解 Wardley 图

在我们深入探讨我创建的策略图之前,我想让读者对 Wardley 图有一个基本的直觉。

简要定义

Wardley 图应被解读为对业务价值链或服务的战略可视化,突出其组件的成熟度和演变。这有助于理解依赖关系,识别机会,并做出关于在哪里集中创新、资源和开发工作的明智决策。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1:作者提供的图像 — 空白 Wardley 图,客户是锚点,因此位于图的顶部

让我们详细说明 Wardley 图的属性:

锚点:在我们所有的图中,锚点是客户。图上所有组件的位置都是相对于客户的。

组件:组件代表为满足客户需求而进行的技术、实践或活动。关联的组件以某种方式相互依赖,主要通过使能。资本、数据和风险可以在关联组件之间流动。

在 AI 策略的目的下,我定义了以下组件:

  • 智能应用:提供给客户的 AI 驱动应用。我保持了这一点的通用性,但读者可以想象任何类型的 AI 驱动应用。这是价值链中最可见的部分,因此在图中最接近客户。

  • 机器学习操作(MLOps):使机器学习/AI 模型在生产中得到管理的实践、人员和技术。要了解更详细的解释,阅读此文

  • 研究与开发(R&D):发现和原型新 AI/ML 模型的实践。这些活动通常在实验室或“沙坑”环境中进行。

  • 数据管理:数据管理涉及以高效、安全的方式组织、存储、检索和维护数据,以确保用户能够访问、可靠和及时获取数据。

  • 基础设施:指所有其他组件所建立的技术 IT 基础设施。

可见性:组件的位置由 y 轴决定,代表沿价值链的可见性。组件距离客户越近,它的可见性就越高。

进化:运动受限于 x 轴,代表地图上给定组件的进化阶段(成熟度)。组件会因外部因素而随着时间发展。

任何组件都有四个进化阶段:

  • 创生:创建新颖、独特的组件或技术。

  • 定制构建: 组件被更好地理解,但仍需针对每个使用场景进行定制。

  • 产品:组件变得标准化,转变为广泛分发的产品或服务。

  • 实用性:组件高度商品化,作为以效率和成本降低为重点的公用服务提供。

现在我们对地图有了基本了解,让我们一起探索 AI 的格局吧!

注意:这是对 Wardley 映射的简化理解,但足以理解我为本文创建的地图。如果你想了解更多,我建议你阅读完整的博客。

阶段 0 的 AI:恐龙时代

我被招聘到一个阶段 0 的公司来构建 AI 战略。我们拥有大量的遗留基础设施,有限的现代技术栈访问权限,以及很少的内部专家来构建智能应用。我怀疑许多读者可以与阶段 0 相关联。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2 — 作者提供的图像:阶段 0 的 AI

请花一些时间理解这个阶段 0 公司的地图。

基础设施:有大量的遗留本地技术基础设施。这些是几十年前由第三方构建的产品,大多数现在已不再得到支持,只有少数几个非常昂贵的专家可以维护。没有人真正理解它们,人们也不愿意干预这些系统,以免引发重大问题。它们几乎被 IT 部门保护,以防止“崩溃”。这些遗留基础设施是可靠的、静态的,显然不利于创新。

数据管理:数据管理系统建立在遗留基础设施之上。几代分析师和工程师构建了定制的数据管道、表视图、仪表盘和报告层,且大多未有文档记录。我们的本地数据仓库被戏称为“数据沼泽”。数据几乎像是无序的西部,一旦有人更改了管道而未通知任何人,你建立的仪表盘可能会随机失败。沼泽中的数据是不可信的。

我偶尔听到有人把自由格式文本字段或 CSV 文件称为杂乱数据。相比之下,我在这里描述的杂乱程度,类似于石油泄漏;自由格式文本输入就像洒出的牛奶。

Phase 0 AI 战略

我们意识到研发、MLOps 和智能应用不能超越数据管理的演变。为了启动 AI 战略,我们首先需要解决这个问题。

作为一个数据科学职能,我们需要对原型所需的数据有更多的控制。我们利用了一款现成的分析工具,允许我们连接到源源不断的数据来源。有限的存储和计算意味着我们需要利用统计方法来适当地抽样数据源。使用开源分析工具进行了数据质量检查。有效地说,我们为研发创建了一个定制的数据管理解决方案。

研发开始时是发现阶段,我们花时间与客户交谈,试图了解智能应用如何能给他们带来好处。我们制定了框架来评估可行性与价值,以便为我们提供一种优先考虑开发计划的方法。

凭借我们临时的数据管理方法和数据实验室,我们设法开发了一些原型应用。然而,从 AI 战略的角度来看,我们遇到了瓶颈。我们已经用尽了所有的途径,下一步的逻辑是从 Phase 0 发展。

基础设施与数据管理的演变

我希望你暂时设想一下你是一个 Phase 0 业务的首席技术官 (CTO)。外部技术的发展会如何影响你的业务?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3 — 作者图像 — 红线表示过渡到未来状态,蓝线表示资本流动,黑色矩形表示对变化的阻力(惯性)

点 1 — 第一个明显的点涉及技术基础设施,它已经被云服务提供商商品化。计算和存储可以作为一种公用事业获得。

点 2 — 因此,数据管理的工具和方法也在不断演变。撰写时,存在流行的云原生数据湖,可以满足广泛的数据管理需求。尽管这还未完全商品化。

考虑到这一点,一个精明的 CTO 可以将他们的 Phase 0 业务的未来状态表示如图 3 所示。

作为 CTO,关注竞争对手,你应该能够预见到更小、更灵活的公司可能已经是云原生的。这将使它们能够投资于研发活动和 MLOps,因为它们的数据管理和基础设施的演变使这成为可能,并且可能具有盈利潜力。该地图将使你能够预测竞争对手如何通过比你更快地开发智能应用来抢占你的市场份额。你可以论证投资于基础设施和数据管理的重要性。

你可能还会预见到可能会有一些对演变的抵制,无论是由于内部摩擦还是之前对自己定制解决方案的成功。在我的阶段 0 经历中,数据沼泽确实受到了一些人的喜爱。有政治力量会拖慢迁移到更高效的数据管理方法的进程。

图 3 中展示的地图帮助你看到,为了推进你的 AI 战略,你应该优先考虑技术基础设施和数据管理的演变。这正是我在阶段 0 银行经历的情况,该战略从实验性 AI 转向了技术基础设施和数据管理方法的成熟。

在阶段 1 业务中的 AI:技术精通、混乱和热情

我有幸参与了阶段 1 银行的战略。我觉得这是大多数刚刚从博士或硕士课程中毕业的数据科学家设想自己能到达的地方。这家银行已经将其技术基础设施外包给了云服务提供商。他们还利用了“产品化”的基于云的数据管理解决方案。

没有公司是完美的,但老实说,这与阶段 0 的银行相差甚远,对我个人来说非常有趣。公司里有数百名数据科学家在探索机器学习和人工智能的新领域。我已经记不清在创新会议上看到的令人惊叹的场景了。然而,前方也有一些大问题。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 4——作者提供的图像——阶段 1 公司快照

AI,只是昂贵的科学实验?

我记得曾经与创新团队的高级成员一起开会。我们每个人都在挠头,试图弄清楚如何将这些精彩的模型投入生产。这些原型都很出色,但说实话,它们对客户没有任何价值。我们不如说是在做昂贵的科学实验。此时,我希望你能想象自己是 CTO 或创新负责人。你会如何解决生产问题?

Wardley 地图:AI 的演变——阶段 2

在撰写本文时,云服务提供商、扩展公司和初创公司一直在解决将人工智能投入生产的问题。一些提供商承诺处理部署机器学习模型所涉及的所有复杂性,而另一些提供商则承诺处理从部署到监控再到重新训练的整个模型生命周期。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5 — 作者提供的图像 — AI 阶段 2 的进化,MLOps 被产品化并作为服务由第三方提供。

考虑到这一点,阶段 1 银行的 CTO 理解了进化的必要性。CTO 选择与云服务提供商合作,构建产品化的 MLOps 服务。这将真正帮助他们在竞争中脱颖而出,因为没有多少建立的银行在大规模交付智能应用。但这不仅仅是构建新技术那么简单。

从战略角度来看,经营阶段 2 的业务需要以完全不同于阶段 1 的方式组织团队。整个业务所需的人才类型也大相径庭。让我们稍微绕一点路来理解这一点。

简要绕行至团队态度

Wardley 绘图给我们提供了态度的概念。态度帮助我们概念化团队在不同进化阶段的工作方式。这里是三种态度的简要概述:

  • 先驱者:先驱者是富有创意的个体,他们探索未知领域,通过核心研究使未来的成功成为可能,尽管面临频繁的失败。

  • 定居者:定居者是实用的远见者,他们通过应用研究和差异化,将原型转化为有利可图的产品,弥合可能与实际之间的差距。

  • 城镇规划者:城镇规划者是效率专家,他们将产品工业化,通过工业研究最大化规模经济,使创新对大众变得可及、可靠且经济实惠。

领导阶段 2 业务

在第一阶段,银行有两种类型的员工:先驱者和城镇规划者。先驱者是进行研发和建立酷炫原型的数据科学家。城镇规划者则管理 IT 基础设施。在我与这家银行合作期间,讨论的重点是如何整合这两个阵营。我们的 Wardley 图会如何建议我们解决这个问题?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 6 — 作者提供的图像 — 领导阶段 2 业务,态度已绘制。关键在左下角

引入定居者

在构建智能应用的背景下,定居者实际上就是你的机器学习和数据工程师。他们的激励是将研究成果转化为价值。作为关注外部因素的尽责 CTO,我们可以看到从我们定制的 MLOps 平台转向更标准化的方法的必要性。

更标准化的方法需要从先驱者转变为定居者。当我们理解这一点后,招聘方法也调整以引进定居者。许多公司犯的错误是让他们的研发数据科学家变成定居者。成功的过渡需要两者,而这些态度往往不会存在于同一个人身上。

阶段 3 的 AI:在 AI 应用中开拓未知领域

图 7 描绘了从第 2 阶段到第 3 阶段业务的演变。作为首席技术官,我们可以利用这种映射方法来预测变化,并重新调整我们的战略。

第 1 点 — 随着 MLOps 整个领域变得像公用事业一样。你可以想象一个情况,其中模型被第三方 API 消耗。

部署:与其让企业开发自己的基础设施来部署机器学习模型,MLOps 实用服务提供商将提供无缝、可扩展的部署解决方案。这可能包括实时预测、批量评分或将模型嵌入应用程序中。

监控:机器学习模型需要对其性能随时间的漂移或输入数据的变化进行监控。作为服务的一部分,提供商将跟踪这些指标,识别问题,并在模型需要调整或重新训练时通知企业。

重新训练:随着新数据的出现或模型性能随时间下降,模型可能需要重新训练。MLOps 实用服务提供商可以处理这一过程,在新数据上重新训练模型,并在对业务操作造成最小干扰的情况下更新部署的模型。

第 2 点 — 数据管理作为公用事业将数据处理视为一种服务,类似于水或电。公司订阅这种服务,可能包括数据存储、安全、处理和分析。这使企业能够专注于其核心竞争力,而公用事业提供商则确保数据管理的质量,提供可扩展性、成本效益和可靠性。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 7 — 作者提供的图像 — 第 3 阶段

先锋的角色再探

第 3 点——在第 3 阶段,先锋(数据科学家)的角色将再次成为焦点。然而,这次他们将拥有更好的装备。他们对 AI 未知领域的探索将不再受到同时开发强大操作流程的需要的限制。相反,他们将能够自由创造和创新。由于潜在的高回报,资本将流入这一新的潜在价值领域。

新市场和专业知识

第 4 点——随着 AI 应用的普及,并开始更深刻地影响社会的各个方面,AI 伦理的重要性也将增加。确保开发的 AI 应用是公平、透明和尊重隐私将变得至关重要。组织需要将 AI 伦理嵌入其创新过程,从设计和开发阶段一直到部署和监控。我们甚至可能看到围绕 AI 伦理和安全创建新的客户需求和市场。

最终思考

随着 MLOps 成为一种实用工具,AI 领域可能会经历显著的变革。AI 的民主化,加上对创新 AI 应用开发的关注以及 AI 伦理的重要性日益增长,预示着未来 AI 将越来越多地融入我们的日常生活。展望未来,企业的任务很明确:通过培养创新导向的思维方式、建立强大的先锋和开拓者团队,并关注不断发展的 AI 伦理领域,为实用 MLOps 时代做好准备。

最后,我要感谢 Simon Wardley 与世界分享这一方法。

感谢阅读。

关注我在 LinkedIn

订阅 Medium 以获取更多我的见解:

[## 通过我的推荐链接加入 Medium - John Adeojo

我分享数据科学项目、经验和专业知识,以帮助您在旅程中前进。您可以通过…

johnadeojo.medium.com

如果您有兴趣将 AI 或数据科学整合到您的业务运营中,我们邀请您预约一次免费的初步咨询:

[## 在线预约 | 数据驱动解决方案

发现我们在帮助企业实现雄心勃勃目标方面的专业知识,提供免费咨询。我们的数据科学家和…

www.data-centric-solutions.com

构建一个 AI 驱动的语言学习应用:从两个 AI 聊天中学习

原文:towardsdatascience.com/building-an-ai-powered-language-learning-app-learning-from-two-ai-chatting-6db7f9b0d7cd

创建一个双聊天机器人语言学习应用的逐步教程,使用 Langchain、OpenAI、gTTS 和 Streamlit

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Shuai Guo

·发表于 Towards Data Science ·25 分钟阅读·2023 年 6 月 26 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

DALL-E 提示:两个友好的机器人相互交谈。

当我第一次开始学习一门新语言时,我喜欢购买那些“对话练习”书籍。我发现这些书籍非常有用,因为它们帮助我理解了语言的运作——不仅仅是语法和词汇,还有人们在日常生活中如何实际使用它。

现在随着大型语言模型(LLMs)的兴起,我想到一个问题:我是否可以以一种更互动、动态和可扩展的形式来复制这些语言学习书籍?我能否利用 LLM 创建一个生成新鲜、按需对话的工具,为语言学习者提供帮助?

这个想法激发了我今天想与大家分享的项目——一个由人工智能驱动的语言学习应用程序,在这个应用中,学习者可以观察并学习两个 AI 聊天机器人进行的用户定义的对话辩论

关于所使用的技术栈,我使用了 Langchain、OpenAI API、gTTS 和 Streamlit 来创建这个应用,用户可以定义角色、场景或辩论主题,让 AI 生成内容。

开发的语言学习应用程序演示。(视频由作者提供)

如果你对它的工作原理感到好奇,那就跟随我一步一步了解构建这个互动双聊天机器人系统的过程 🗺️📍🚶‍♀️。

你可以在这里💻找到完整的源代码。在这篇博客中,我们还将介绍关键的代码片段以解释这些想法。

既然如此,我们开始吧!

内容目录

· 1. 项目概述

· 2. 前置条件

∘ 2.1 LangChain

∘ 2.2 ConversationChain

· 3. 项目设计

∘ 3.1 开发单一聊天机器人

∘ 3.2 开发双聊天机器人系统

· 4. 使用 Streamlit 的应用界面设计

· 5. 学习成果与未来扩展

· 6. 结论

1. 项目概述

如前所述,我们的目标是创建一个由两个对话式 AI 或聊天机器人驱动的独特语言学习应用程序。这个应用程序的创新之处在于让这些聊天机器人相互互动,创造出逼真的目标语言对话。用户可以观察这些 AI 驱动的对话,将其作为语言学习资源,并理解所选语言的实际使用。

在我们的应用程序中,用户应具备根据自身需求定制学习体验的灵活性。他们可以调整多个设置,包括目标语言、学习模式、会话时长和熟练程度。

目标语言 🔤

用户可以选择他们希望学习的语言。这个选择将指导聊天机器人在互动过程中使用的语言。目前,我已经支持了英语——‘en’,德语——‘de’,西班牙语——‘es’,和法语——‘fr’,但只要 GPT 模型对这些语言有足够的知识,添加更多语言是微不足道的。

学习模式 📖

这个设置允许用户选择聊天机器人之间的对话风格。在**“对话”模式下,用户可以定义角色**(例如,顾客和服务员)和动作(点餐和接单),并指定一个场景(在餐厅),聊天机器人将模拟一个逼真的对话。在**“辩论”模式下,用户被提示输入一个辩论话题**(我们是否应该采用核能?)。然后,聊天机器人会围绕提供的话题进行激烈的辩论。

应用程序的界面应该是响应式的,并根据用户选择的学习模式动态调整,以提供无缝的用户体验。

会话时长 ⏰

会话时长设置让用户控制每次聊天机器人对话或辩论的持续时间。这意味着他们可以进行简短的快速对话,或根据个人喜好进行更长时间、更深入的讨论。

熟练程度 🏆

这个设置将聊天机器人的对话复杂性量身定制为用户的语言能力水平。初学者可能更喜欢简单的对话,而更高级的学习者则可以处理复杂的辩论或讨论。

一旦用户指定了这些设置,他们就可以启动会话,观看 AI 聊天机器人如何根据用户的偏好进行动态和互动的对话。我们的整体工作流程可以如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

工作流程概述。用户指定的设置将用于配置提示,这些提示将提供给聊天机器人以生成对话。获得的脚本(连同用户设置)将用于填充应用程序界面。(图片由作者提供)

2. 前提条件

在我们深入开发应用程序之前,让我们熟悉一下我们将使用的工具。在这一部分,我们将简要介绍 LangChain 库,特别是 ConversationChain 模块,它作为我们应用程序的核心部分。

2.1 LangChain

构建一个由大型语言模型(LLMs)驱动的应用程序涉及许多复杂性。你需要通过 API 调用与语言模型提供者进行接口连接,将这些模型与各种数据源连接,处理用户互动的历史记录,并设计执行复杂任务的管道。这正是 LangChain 库发挥作用的地方。

LangChain是一个旨在简化基于大语言模型(LLM)应用程序开发的框架。它提供了一系列组件,解决了上述常见痛点。无论是管理与语言模型提供者的互动,组织数据连接,维护历史互动的记忆,还是定义复杂的任务管道,LangChain 都能应对自如。

LangChain 介绍的一个关键概念是“Chain”。本质上,链允许我们将多个组件组合在一起,以创建一个统一的应用程序。例如,LangChain 中的一个基本链类型是 LLMChain。它创建了一个管道,首先使用用户提供的输入键值格式化提示模板,然后将格式化的指令传递给 LLM,最后返回 LLM 的输出。

LangChain 主持各种链类型,包括 RetrievalQAChain,用于对文档进行问答,SummarizationChain,用于总结多个文档,以及我们今天的重点,即 ConversationChain

2.2 ConversationChain

ConversationChain 用于通过提供一个消息交换和存储对话历史的框架来促进互动对话。以下是一个示例代码片段,以说明其用法:

from langchain.chains import ConversationChain

# Create conversation chain
conversation = ConversationChain(memory, prompt, llm)

# Run conversation chain
conversation.predict(input="Hi there!")

# Obtain the LLM response: "Hello! How can I assist you today?"

# We can keep calling conversation chain
conversation.predict(input="I'm doing well! Just having a conversation with an AI.")
# Obtain the LLM response: "That sounds like fun! I'm happy to chat with you. Is there anything specific you'd like to talk about?"

在这个示例中,ConversationChain 接受三个输入,memory,一个持有互动历史的 LangChain 组件;prompt,输入到 LLM 的内容;以及 llm,核心的大型语言模型(例如,GPT-3.5-Turbo 等)。

一旦 ConversationChain 对象被实例化,我们只需使用用户输入调用 conversation.predict() 即可获得 LLM 的响应。ConversationChain 的便利之处在于,我们实际上可以多次调用 conversation.predict(),它会自动在后台记录消息历史。

在下一部分,我们将利用 ConversationChain 的强大功能创建我们的聊天机器人,并深入探讨记忆、提示模板和 LLM 的定义与使用。

如果你想了解更多关于 LangChain 的信息,可以查看他们的官方文档。此外,这个YouTube 播放列表也提供了全面的实践介绍。

3. 项目设计

既然我们对要构建的内容和工具有了明确的了解,就该动手编写代码了!在这一部分,我们将专注于创建双聊天机器人交互的细节。首先,我们将探讨单一聊天机器人的类定义,然后扩展这一定义以创建一个双聊天机器人类,使我们的两个聊天机器人能够互相互动。我们将把使用 Streamlit 设计应用界面的工作留到第四部分。

3.1 开发一个单一的聊天机器人

在这一小节中,我们将一起开发一个单一的聊天机器人,随后将其集成到双聊天机器人系统中。让我们从整体的类设计开始,然后将注意力转向提示工程。

🏗️ 类设计

我们的聊天机器人类应该能够管理一个单独的聊天机器人。这包括实例化一个以用户指定的 LLM 作为基础的聊天机器人,根据用户的意图提供指令,并支持交互式的多轮对话。考虑到这一点,让我们开始编码吧。

首先,导入必要的库:

import os
import openai
from langchain.prompts import (
    ChatPromptTemplate, 
    MessagesPlaceholder, 
    SystemMessagePromptTemplate, 
    HumanMessagePromptTemplate
)
from langchain.prompts import PromptTemplate
from langchain.chains import LLMChain
from langchain.chains import ConversationChain
from langchain.chat_models import ChatOpenAI
from langchain.memory import ConversationBufferMemory

接下来,我们定义类构造函数:

class Chatbot:
    """Class definition for a single chatbot with memory, created with LangChain."""

    def __init__(self, engine):
        """Select backbone large language model, as well as instantiate 
        the memory for creating language chain in LangChain.
        """

        # Instantiate llm
        if engine == 'OpenAI':
            # Reminder: need to set up openAI API key 
            # (e.g., via environment variable OPENAI_API_KEY)
            self.llm = ChatOpenAI(
                model_name="gpt-3.5-turbo",
                temperature=0.7
            )

        else:
            raise KeyError("Currently unsupported chat model type!")

        # Instantiate memory
        self.memory = ConversationBufferMemory(return_messages=True)

目前,你只能选择使用原生的 OpenAI API。然而,添加更多后端 LLM 是很简单的,因为 LangChain 支持多种类型(例如 Azure OpenAI 端点、Anthropic 聊天模型、Google Vertex AI 上的 PaLM API 等)。

除了 LLM,我们还需要实例化另一个重要的组件——记忆,它跟踪对话历史。在这里,我们使用ConversationBufferMemory来实现这一目的,它仅仅是在聊天机器人的当前输入前添加最后几条输入/输出。这是 LangChain 提供的最简单的记忆类型,对于我们当前的目的已经足够。

要全面了解其他类型的记忆,请参考官方文档

继续,我们需要一个类方法,允许我们给聊天机器人下达指令并与其对话。这就是self.instruct()的作用:

def instruct(self, role, oppo_role, language, scenario, 
             session_length, proficiency_level, 
             learning_mode, starter=False):
    """Determine the context of chatbot interaction. 
    """

    # Define language settings
    self.role = role
    self.oppo_role = oppo_role
    self.language = language
    self.scenario = scenario
    self.session_length = session_length
    self.proficiency_level = proficiency_level
    self.learning_mode = learning_mode
    self.starter = starter

    # Define prompt template
    prompt = ChatPromptTemplate.from_messages([
        SystemMessagePromptTemplate.from_template(self._specify_system_message()),
        MessagesPlaceholder(variable_name="history"),
        HumanMessagePromptTemplate.from_template("{input}")
    ])

    # Create conversation chain
    self.conversation = ConversationChain(memory=self.memory, prompt=prompt, 
                                          llm=self.llm, verbose=False)
  • 我们定义了一些设置,以便用户可以自定义他们的学习体验。

除了在“第一部分 项目概述”中提到的内容外,我们还有四个新的属性:

self.role/self.oppo_role: 这个属性的形式是一个字典,用于记录角色名称及其对应的动作。例如:

self.role = {'name': 'Customer', 'action': 'ordering food'}

self.oppo_role表示与当前聊天机器人进行对话的另一个聊天机器人所扮演的角色。这是重要的,因为当前聊天机器人需要了解它正在与谁沟通,以提供必要的上下文信息。

self.scenario 为对话设置了场景。对于“对话”学习模式,self.scenario 代表对话发生的地方。

正在发生;对于“辩论”模式,self.scenario 代表辩论的话题。

最后,self.starter 只是一个布尔标志,用于指示当前聊天机器人是否会发起对话。

  • 我们为聊天机器人构建提示。

在 OpenAI 中,一个聊天模型通常接受一系列消息作为输入,并返回模型生成的消息作为输出。LangChain 支持 SystemMessageAIMessageHumanMessageSystemMessage 帮助设置聊天机器人的行为,AIMessage 存储以前聊天机器人的响应,HumanMessage 提供聊天机器人需要回应的请求或评论。

LangChain 方便地提供了 PromptTemplate 来简化提示生成和处理。对于聊天机器人应用,我们需要为所有三种消息类型指定 PromptTemplate。最关键的部分是设置 SystemMessage,它控制聊天机器人的行为。我们有一个单独的方法 self._specify_system_message() 来处理这个问题,稍后我们会详细讨论。

  • 最后,我们把所有部分整合在一起,构建一个 ConversationChain

🖋️ 提示设计

我们现在的重点是指导聊天机器人根据用户的需求参与对话。为此,我们有 self._specify_system_message() 方法。该方法的签名如下所示:

def _specify_system_message(self):
    """Specify the behavior of the chatbot, which consists of the following
       aspects:

    - general context: conducting conversation/debate under given scenario
    - the language spoken
    - purpose of the simulated conversation/debate
    - language complexity requirement
    - exchange length requirement
    - other nuance constraints

    Outputs:
    --------
    prompt: instructions for the chatbot.
    """ 

本质上,这个方法编译一个字符串,然后将其输入到 SystemMessagePromptTemplate.from_template() 以指示聊天机器人,如上面 self.instruct() 方法的定义所示。我们将在接下来的部分中分析这个“长字符串”,以了解每个语言学习需求如何融入提示中。

1️⃣ 会话长度

会话长度通过直接指定在一个会话中可以发生的最大交换次数来控制。这些数字目前是硬编码的。

# Determine the number of exchanges between two bots
exchange_counts_dict = {
    'Short': {'Conversation': 8, 'Debate': 4},
    'Long': {'Conversation': 16, 'Debate': 8}
}
exchange_counts = exchange_counts_dict[self.session_length][self.learning_mode]

2️⃣ 聊天机器人在一次交换中可以说的句子数量

除了限制允许的总交换次数外,限制聊天机器人在一次交换中可以说多少也是有益的,或者等效地,限制句子数量。

在我的实验中,通常不需要在“对话”模式中限制这个,因为聊天机器人模拟真实对话,往往会在合理的长度内发言。然而,在“辩论”模式下,需要施加限制,否则聊天机器人可能会继续发言,最终生成一篇“文章” 😆。

类似于限制会话长度,限制演讲长度的数字也是硬编码的,并且与用户在目标语言中的熟练程度相对应:

# Determine number of sentences in one debate round
argument_num_dict = {
    'Beginner': 4,
    'Intermediate': 6,
    'Advanced': 8
} 

3️⃣ 确定演讲复杂度

在这里,我们调整聊天机器人可以使用的语言复杂度级别:

if self.proficiency_level == 'Beginner':
    lang_requirement = """use as basic and simple vocabulary and
    sentence structures as possible. Must avoid idioms, slang, 
    and complex grammatical constructs."""

elif self.proficiency_level == 'Intermediate':
    lang_requirement = """use a wider range of vocabulary and a variety of sentence structures. 
    You can include some idioms and colloquial expressions, 
    but avoid highly technical language or complex literary expressions."""

elif self.proficiency_level == 'Advanced':
    lang_requirement = """use sophisticated vocabulary, complex sentence structures, idioms, 
    colloquial expressions, and technical language where appropriate."""

else:
    raise KeyError('Currently unsupported proficiency level!')

4️⃣ 把所有内容整合起来!

以下是不同学习模式下的指令示例:

# Compile bot instructions 
if self.learning_mode == 'Conversation':
    prompt = f"""You are an AI that is good at role-playing. 
    You are simulating a typical conversation happened {self.scenario}. 
    In this scenario, you are playing as a {self.role['name']} {self.role['action']}, speaking to a 
    {self.oppo_role['name']} {self.oppo_role['action']}.
    Your conversation should only be conducted in {self.language}. Do not translate.
    This simulated {self.learning_mode} is designed for {self.language} language learners to learn real-life 
    conversations in {self.language}. You should assume the learners' proficiency level in 
    {self.language} is {self.proficiency_level}. Therefore, you should {lang_requirement}.
    You should finish the conversation within {exchange_counts} exchanges with the {self.oppo_role['name']}. 
    Make your conversation with {self.oppo_role['name']} natural and typical in the considered scenario in 
    {self.language} cultural."""

elif self.learning_mode == 'Debate':
    prompt = f"""You are an AI that is good at debating. 
    You are now engaged in a debate with the following topic: {self.scenario}. 
    In this debate, you are taking on the role of a {self.role['name']}. 
    Always remember your stances in the debate.
    Your debate should only be conducted in {self.language}. Do not translate.
    This simulated debate is designed for {self.language} language learners to 
    learn {self.language}. You should assume the learners' proficiency level in {self.language} 
    is {self.proficiency_level}. Therefore, you should {lang_requirement}.
    You will exchange opinions with another AI (who plays the {self.oppo_role['name']} role) 
    {exchange_counts} times. 
    Everytime you speak, you can only speak no more than 
    {argument_num_dict[self.proficiency_level]} sentences."""

else:
    raise KeyError('Currently unsupported learning mode!')

5️⃣ 谁先发言?

最后,我们指示聊天机器人是否应该先发言或等待对方 AI 的回应:

# Give bot instructions
if self.starter:
    # In case the current bot is the first one to speak
    prompt += f"You are leading the {self.learning_mode}. \n"

else:
    # In case the current bot is the second one to speak
    prompt += f"Wait for the {self.oppo_role['name']}'s statement."

现在我们已经完成了提示设计🎉 简要总结一下,这就是我们迄今为止开发的内容:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

单一聊天机器人类。(图片由作者提供)

3.2 开发双聊天机器人系统

现在我们来到了令人兴奋的部分!在这一小节中,我们将开发一个双聊天机器人类,让两个聊天机器人相互互动💬💬

🏗️ 类设计

由于之前开发的单一聊天机器人类,我们可以轻松地在类构造函数中实例化两个聊天机器人:

class DualChatbot:
    """Class definition for dual-chatbots interaction system, 
      created with LangChain."""

    def __init__(self, engine, role_dict, language, scenario, proficiency_level, 
                 learning_mode, session_length):

        # Instantiate two chatbots
        self.engine = engine
        self.proficiency_level = proficiency_level
        self.language = language
        self.chatbots = role_dict
        for k in role_dict.keys():
            self.chatbots[k].update({'chatbot': Chatbot(engine)})

        # Assigning roles for two chatbots
        self.chatbots['role1']['chatbot'].instruct(role=self.chatbots['role1'], 
                                                   oppo_role=self.chatbots['role2'], 
                                                   language=language, scenario=scenario, 
                                                   session_length=session_length, 
                                                   proficiency_level=proficiency_level, 
                                                   learning_mode=learning_mode, starter=True)

        self.chatbots['role2']['chatbot'].instruct(role=self.chatbots['role2'], 
                                                   oppo_role=self.chatbots['role1'], 
                                                   language=language, scenario=scenario, 
                                                   session_length=session_length, 
                                                   proficiency_level=proficiency_level, 
                                                   learning_mode=learning_mode, starter=False) 

        # Add session length
        self.session_length = session_length

        # Prepare conversation
        self._reset_conversation_history()

self.chatbots是一个字典,用于存储与两个机器人相关的信息:

# For "conversation" mode
self.chatbots= {
                'role1': {'name': 'Customer', 
                          'action': 'ordering food',
                          'chatbot': Chatbot()},
                'role2': {'name': 'Waitstaff', 
                          'action': 'taking the order',
                          'chatbot': Chatbot()}
              }

# For "debate" mode
self.chatbots= {
                'role1': {'name': 'Proponent', 
                          'chatbot': Chatbot()},
                'role2': {'name': 'Opponent', 
                          'chatbot': Chatbot()}
              }

self._reset_conversation_history用于启动一个新的对话历史并提供初始指令给聊天机器人:

def _reset_conversation_history(self):
    """Reset the conversation history.
    """    
    # Placeholder for conversation history
    self.conversation_history = []

    # Inputs for two chatbots
    self.input1 = "Start the conversation."
    self.input2 = "" 

为了促进两个聊天机器人之间的互动,我们使用了self.step()方法。此方法允许两个机器人之间进行一轮互动:

def step(self):
    """Make one exchange round between two chatbots. 
    """        

    # Chatbot1 speaks
    output1 = self.chatbots['role1']['chatbot'].conversation.predict(input=self.input1)
    self.conversation_history.append({"bot": self.chatbots['role1']['name'], "text": output1})

    # Pass output of chatbot1 as input to chatbot2
    self.input2 = output1

    # Chatbot2 speaks
    output2 = self.chatbots['role2']['chatbot'].conversation.predict(input=self.input2)
    self.conversation_history.append({"bot": self.chatbots['role2']['name'], "text": output2})

    # Pass output of chatbot2 as input to chatbot1
    self.input1 = output2

    # Translate responses
    translate1 = self.translate(output1)
    translate2 = self.translate(output2)

    return output1, output2, translate1, translate2

请注意,我们嵌入了一个名为self.translate()的方法。此方法的目的是将脚本翻译成英语。此功能对于语言学习者可能很有用,因为他们可以理解在目标语言中生成的对话的含义。

为实现翻译功能,我们可以使用基本的LLMChain,它需要一个后台 LLM 模型和一个指令提示:

 def translate(self, message):
      """Translate the generated script into English. 
      """        

      if self.language == 'English':
          # No translation performed
          translation = 'Translation: ' + message

      else:
          # Instantiate translator
          if self.engine == 'OpenAI':
              # Reminder: need to set up openAI API key 
              # (e.g., via environment variable OPENAI_API_KEY)
              self.translator = ChatOpenAI(
                  model_name="gpt-3.5-turbo",
                  temperature=0.7
              )

          else:
              raise KeyError("Currently unsupported translation model type!")

          # Specify instruction
          instruction = """Translate the following sentence from {src_lang} 
          (source language) to {trg_lang} (target language).
          Here is the sentence in source language: \n
          {src_input}."""

          prompt = PromptTemplate(
              input_variables=["src_lang", "trg_lang", "src_input"],
              template=instruction,
          )

          # Create a language chain
          translator_chain = LLMChain(llm=self.translator, prompt=prompt)
          translation = translator_chain.predict(src_lang=self.language,
                                              trg_lang="English",
                                              src_input=message)

      return translation

最后,语言学习者能够获得生成对话脚本的关键语言学习点的总结可能是有益的,无论是关键词汇、语法点还是功能短语。为此,我们可以包含一个self.summary()方法:

def summary(self, script):
    """Distill key language learning points from the generated scripts. 
    """  

    # Instantiate summary bot
    if self.engine == 'OpenAI':
        # Reminder: need to set up openAI API key 
        # (e.g., via environment variable OPENAI_API_KEY)
        self.summary_bot = ChatOpenAI(
            model_name="gpt-3.5-turbo",
            temperature=0.7
        )

    else:
        raise KeyError("Currently unsupported summary model type!")

    # Specify instruction
    instruction = """The following text is a simulated conversation in 
    {src_lang}. The goal of this text is to aid {src_lang} learners to learn
    real-life usage of {src_lang}. Therefore, your task is to summarize the key 
    learning points based on the given text. Specifically, you should summarize 
    the key vocabulary, grammar points, and function phrases that could be important 
    for students learning {src_lang}. Your summary should be conducted in English, but
    use examples from the text in the original language where appropriate.
    Remember your target students have a proficiency level of 
    {proficiency} in {src_lang}. You summarization must match with their 
    proficiency level. 

    The conversation is: \n
    {script}."""

    prompt = PromptTemplate(
        input_variables=["src_lang", "proficiency", "script"],
        template=instruction,
    )

    # Create a language chain
    summary_chain = LLMChain(llm=self.summary_bot, prompt=prompt)
    summary = summary_chain.predict(src_lang=self.language,
                                    proficiency=self.proficiency_level,
                                    script=script)

    return summary

类似于self.translate()方法,我们使用了一个基本的LLMChain来执行所需的任务。请注意,我们明确要求语言模型根据用户的熟练程度总结关键的语言学习点。

有了这一点,我们已经完成了双聊天机器人类的开发🥂 简要总结一下,这就是我们迄今为止开发的内容:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

单一聊天机器人 & 双聊天机器人类。(图片由作者提供)

4. 使用 Streamlit 进行应用程序界面设计

我们现在准备开发用户界面🖥️ 对于这个项目,我们将使用 Streamlit 库来构建前端。

如果你不熟悉,Streamlit 是一个开源 Python 库,用于创建专注于数据科学和机器学习的互动式 Web 应用程序。它通过提供易于使用的 API、即时更新的实时代码重载、用于用户输入的互动小部件、对数据可视化库的支持以及包含丰富媒体的能力,简化了构建和部署应用程序的过程。

让我们从一个新的 Python 脚本 app.py 开始,并导入必要的库:

import streamlit as st
from streamlit_chat import message
from chatbot import DualChatbot
import time
from gtts import gTTS
from io import BytesIO

除了主要的streamlit库,我们还导入了streamlit_chat库,这是一个由社区构建的 Streamlit 组件,专门用于创建聊天机器人用户界面。我们之前开发的DualChatbot类存储在chatbot.py文件中,因此也需要导入该文件。最后,我们导入gTTS,即Google Text-to-Speech,以为这个项目中的机器人生成的对话脚本添加音频。

在配置 Streamlit 界面之前,让我们首先定义语言学习设置:

# Define the language learning settings
LANGUAGES = ['English', 'German', 'Spanish', 'French']
SESSION_LENGTHS = ['Short', 'Long']
PROFICIENCY_LEVELS = ['Beginner', 'Intermediate', 'Advanced']
MAX_EXCHANGE_COUNTS = {
    'Short': {'Conversation': 8, 'Debate': 4},
    'Long': {'Conversation': 16, 'Debate': 8}
}
AUDIO_SPEECH = {
    'English': 'en',
    'German': 'de',
    'Spanish': 'es',
    'French': 'fr'
}
AVATAR_SEED = [123, 42]

# Define backbone llm
engine = 'OpenAI'

AVATAR_SEED用于为不同的聊天机器人生成不同的头像图标。

我们开始设置用户界面的基本布局,并建立供用户选择的选项:

# Set the title of the app
st.title('Language Learning App 🌍📖🎓')

# Set the description of the app
st.markdown("""
This app generates conversation or debate scripts to aid in language learning 🎯 

Choose your desired settings and press 'Generate' to start 🚀
""")

# Add a selectbox for learning mode
learning_mode = st.sidebar.selectbox('Learning Mode 📖', ('Conversation', 'Debate'))

if learning_mode == 'Conversation':
    role1 = st.sidebar.text_input('Role 1 🎭')
    action1 = st.sidebar.text_input('Action 1 🗣️')
    role2 = st.sidebar.text_input('Role 2 🎭')
    action2 = st.sidebar.text_input('Action 2 🗣️')
    scenario = st.sidebar.text_input('Scenario 🎥')
    time_delay = 2

    # Configure role dictionary
    role_dict = {
        'role1': {'name': role1, 'action': action1},
        'role2': {'name': role2, 'action': action2}
    }

else:
    scenario = st.sidebar.text_input('Debate Topic 💬')

    # Configure role dictionary
    role_dict = {
        'role1': {'name': 'Proponent'},
        'role2': {'name': 'Opponent'}
    }
    time_delay = 5

language = st.sidebar.selectbox('Target Language 🔤', LANGUAGES)
session_length = st.sidebar.selectbox('Session Length ⏰', SESSION_LENGTHS)
proficiency_level = st.sidebar.selectbox('Proficiency Level 🏆', PROFICIENCY_LEVELS)

注意引入了time_delay变量。它用于指定显示两个连续消息之间的等待时间。如果此延迟设置为零,则两个聊天机器人之间生成的交换将迅速出现在应用程序中(仅受限于 OpenAI 的响应时间)。然而,为了用户体验,在下一次交换出现之前,允许用户有足够的时间阅读生成的消息可能是有益的。

接下来,我们初始化 Streamlit 会话状态以存储用户特定的会话数据:

if "bot1_mesg" not in st.session_state:
    st.session_state["bot1_mesg"] = []

if "bot2_mesg" not in st.session_state:
    st.session_state["bot2_mesg"] = []

if 'batch_flag' not in st.session_state:
    st.session_state["batch_flag"] = False

if 'translate_flag' not in st.session_state:
    st.session_state["translate_flag"] = False

if 'audio_flag' not in st.session_state:
    st.session_state["audio_flag"] = False

if 'message_counter' not in st.session_state:
    st.session_state["message_counter"] = 0

在这里我们回答两个问题:

1️⃣ 首先,我们为什么需要“session_state”?

在 Streamlit 中,每次用户与应用程序交互时,Streamlit 会从头到尾重新运行整个脚本,更新应用程序的输出。然而,Streamlit 的这种反应性特征在你想要维护用户特定数据或在不同交互或页面之间保留状态时可能会成为挑战。由于 Streamlit 在每次用户交互时都会重新加载脚本,常规 Python 变量会丢失其值,应用程序将重置为初始状态。

这就是session_state发挥作用的地方。Streamlit 中的会话状态提供了一种存储和检索数据的方式,这些数据在用户会话期间会持久存在,即使应用程序被重新加载或用户在不同组件或页面之间导航时。它允许你保持状态信息并为每个用户保留应用程序的上下文。

2️⃣ 其次,session_state中存储了哪些变量?

bot1_mesg”是一个列表,其中每个元素都是一个字典,包含第一台聊天机器人说的话。它具有以下键:“role”、“content”和“translation”。同样的定义适用于“bot2_mesg”。

batch_flag” 是一个布尔标志,用于指示对话交流是否一次性显示或有时间延迟。在当前设计中,当两个聊天机器人之间的对话首次生成时,它们的聊天将会有时间延迟地出现。之后,用户可能希望查看生成对话的翻译或添加音频,存储的对话消息(在“bot1_mesg”和“bot2_mesg”中)将一次性显示。这是有利的,因为我们不需要再次调用 OpenAI API,从而减少成本和延迟。

translate_flag” 和 “audio_flag” 用于指示翻译和/或音频是否会显示在原始对话旁边。

message_counter” 是一个计数器,每当一个来自聊天机器人的消息显示时,它会加一。这个想法是将消息 ID 与此计数器关联,因为 Streamlit 要求每个 UI 组件必须有唯一的 ID。

现在我们可以引入让两个聊天机器人互动并生成对话的逻辑:

if 'dual_chatbots' not in st.session_state:

    if st.sidebar.button('Generate'):

        # Add flag to indicate if this is the first time running the script
        st.session_state["first_time_exec"] = True 

        with conversation_container:
            if learning_mode == 'Conversation':
                st.write(f"""#### The following conversation happens between 
                                {role1} and {role2} {scenario} 🎭""")

            else:
                st.write(f"""#### Debate 💬: {scenario}""")

            # Instantiate dual-chatbot system
            dual_chatbots = DualChatbot(engine, role_dict, language, scenario, 
                                        proficiency_level, learning_mode, session_length)
            st.session_state['dual_chatbots'] = dual_chatbots

            # Start exchanges
            for _ in range(MAX_EXCHANGE_COUNTS[session_length][learning_mode]):
                output1, output2, translate1, translate2 = dual_chatbots.step()

                mesg_1 = {"role": dual_chatbots.chatbots['role1']['name'], 
                        "content": output1, "translation": translate1}
                mesg_2 = {"role": dual_chatbots.chatbots['role2']['name'], 
                        "content": output2, "translation": translate2}

                new_count = show_messages(mesg_1, mesg_2, 
                                          st.session_state["message_counter"],
                                          time_delay=time_delay, batch=False,
                                          audio=False, translation=False)
                st.session_state["message_counter"] = new_count

                # Update session state
                st.session_state.bot1_mesg.append(mesg_1)
                st.session_state.bot2_mesg.append(mesg_2)

当第一次运行脚本时,会话状态中将没有“dual_chatbots”键(因为双聊天机器人尚未创建)。因此,当用户点击侧边栏上的“Generate”按钮时,上述代码片段将被执行。两个聊天机器人将往返聊天给定次数,所有对话消息都记录在会话状态中。show_message() 函数是一个辅助函数,旨在成为唯一的接口来样式化消息显示。我们将在本节末尾再次回到它。

现在,如果用户与应用互动并更改一些设置,Streamlit 将从头开始重新运行整个脚本。由于我们已经生成了所需的对话脚本,因此无需再次调用 OpenAI API。相反,我们可以简单地检索存储的信息:

if 'dual_chatbots' in st.session_state:  

    # Show translation 
    if translate_col.button('Translate to English'):
        st.session_state['translate_flag'] = True
        st.session_state['batch_flag'] = True

    # Show original text
    if original_col.button('Show original'):
        st.session_state['translate_flag'] = False
        st.session_state['batch_flag'] = True

    # Append audio
    if audio_col.button('Play audio'):
        st.session_state['audio_flag'] = True
        st.session_state['batch_flag'] = True

    # Retrieve generated conversation & chatbots
    mesg1_list = st.session_state.bot1_mesg
    mesg2_list = st.session_state.bot2_mesg
    dual_chatbots = st.session_state['dual_chatbots']

    # Control message appearance
    if st.session_state["first_time_exec"]:
        st.session_state['first_time_exec'] = False

    else:
        # Show complete message
        with conversation_container:

            if learning_mode == 'Conversation':
                st.write(f"""#### {role1} and {role2} {scenario} 🎭""")

            else:
                st.write(f"""#### Debate 💬: {scenario}""")

            for mesg_1, mesg_2 in zip(mesg1_list, mesg2_list):
                new_count = show_messages(mesg_1, mesg_2, 
                                        st.session_state["message_counter"],
                                        time_delay=time_delay,
                                        batch=st.session_state['batch_flag'],
                                        audio=st.session_state['audio_flag'],
                                        translation=st.session_state['translate_flag'])
                st.session_state["message_counter"] = new_count

请注意会话状态中还有一个名为“first_time_exec”的标志。这个标志用于指示原始生成的脚本是否已经在应用中显示。如果我们去掉这个检查,应用第一次运行时相同的消息将会出现两次。

剩下的唯一任务是在 UI 中加入关键学习点的总结。为此,我们可以使用 st.expander。在 Streamlit 中,st.expander 对于我们希望以简洁形式呈现的大量内容或信息很有用,最初隐藏视图。当用户点击扩展器时,内容将展开或折叠,从而显示或隐藏额外的细节。

 # Create summary for key learning points
    summary_expander = st.expander('Key Learning Points')
    scripts = []
    for mesg_1, mesg_2 in zip(mesg1_list, mesg2_list):
        for i, mesg in enumerate([mesg_1, mesg_2]):
            scripts.append(mesg['role'] + ': ' + mesg['content'])

    # Compile summary
    if "summary" not in st.session_state:
        summary = dual_chatbots.summary(scripts)
        st.session_state["summary"] = summary
    else:
        summary = st.session_state["summary"]

    with summary_expander:
        st.markdown(f"**Here is the learning summary:**")
        st.write(summary)

由于关键学习点的总结也是通过调用 OpenAI API 生成的,我们可以将生成的总结保存到会话状态中,以便如果脚本第二次运行时可以检索这些内容。

最后,让我们用辅助函数 show_message 完成 Streamlit UI 设计:

def show_messages(mesg_1, mesg_2, message_counter,
                  time_delay, batch=False, audio=False,
                  translation=False):
    """Display conversation exchanges. This helper function supports
    displaying original texts, translated texts, and audio speech.

    Output:
    -------
    message_counter: updated counter for ID key
    """    

    for i, mesg in enumerate([mesg_1, mesg_2]):
        # Show original exchange ()
        message(f"{mesg['content']}", is_user=i==1, avatar_style="bottts", 
                seed=AVATAR_SEED[i],
                key=message_counter)
        message_counter += 1

        # Mimic time interval between conversations
        # (this time delay only appears when generating 
        # the conversation script for the first time)
        if not batch:
            time.sleep(time_delay)

        # Show translated exchange
        if translation:
            message(f"{mesg['translation']}", is_user=i==1, avatar_style="bottts", 
                    seed=AVATAR_SEED[i], 
                    key=message_counter)
            message_counter += 1

        # Append autio to the exchange
        if audio:
            tts = gTTS(text=mesg['content'], lang=AUDIO_SPEECH[language])  
            sound_file = BytesIO()
            tts.write_to_fp(sound_file)
            st.audio(sound_file)

    return message_counter

有几个要点需要进一步解释:

1️⃣ message() 对象

这部分属于 streamlit_chat 库,用于显示消息。在最简单的形式下,我们有:

import streamlit as st
from streamlit_chat import message

message("Hellp, I am a Chatbot, how may I help you?") 
message("Hey, what's a chatbot", is_user=True) 

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(图片来自 streamlit_chat GitHub 仓库)

其中参数 is_user 决定消息是左对齐还是右对齐。在我们的 show_message 代码片段中,我们还指定了 avatar_styleseed 来设置两个聊天机器人的头像图标。key 参数仅用于为每条消息分配唯一的 ID,这是 Streamlit 所要求的。

2️⃣ 语音合成

在这里,我们使用 gTTS 库基于生成的脚本创建目标语言的音频语音。这个库使用起来非常简单,但它有一个限制:你只能使用一种声音。在生成音频对象后,我们可以使用 st.audio 为应用中的每条消息创建一个音频播放器。

太棒了!我们现在已经完成了 UI 设计 😃 在终端中输入以下命令:

streamlit run app.py

你应该能在浏览器中看到应用,并能够与其互动。干得好!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

开发的语言学习应用界面。(作者提供的图片)

5. 学习与未来扩展

在结束之前,我想与你分享一些来自这个项目的关键学习和未来扩展的潜在方向。

1️⃣ 如何结束对话?

如果想要正确实现,这个问题实际上比看起来要复杂得多。理想情况下,我们希望对话自然结束。然而,在我的一些实验中,我注意到聊天机器人在对话结束时会不断互相说“谢谢”或“再见”,这不必要地延长了对话。一些可能的解决方案包括:

  1. 交换轮次的硬限制:这可能是最简单的解决方案,也是我们在这个项目中采用的解决方案。然而,它可能并不总是理想的,因为它可能导致对话被过早终止。作为解决方法,我们已经在 SystemMessage 中指示机器人在设定的交换轮次内完成对话。

  2. 使用“信号词”:聊天机器人可以被编程以在认为对话自然结束时说出特定的“信号词”(例如,“对话结束”)。然后可以实现逻辑来检测这些“信号词”并相应地结束循环。

  3. 对话的后处理:一旦聊天机器人生成了对话,可以部署另一个 LLM 作为“编辑器”来修剪对话。这可能是一个有效的方法。然而,其缺点可能包括设计额外的提示、调用 OpenAI API 可能产生的额外费用以及增加的延迟。

2️⃣ 如何控制语言复杂性?

根据我的经验,开发的聊天机器人似乎在遵循语言复杂度的指示方面存在困难:有时即使熟练度设定为“初学者”,也会出现“中级”语言使用。这可能是因为当前的提示设计不足以明确区分不同复杂度级别之间的细微差别。

解决这个问题有几种方法:首先,我们可以进行上下文学习。也就是说,我们提供示例给聊天机器人,并展示我们期望在不同复杂度级别中使用的语言。另一种方法与我们之前讨论的类似:我们可以使用另一个 LLM 来调整对话的复杂性。实质上,这个额外的 LLM 可以利用生成的脚本作为起点,并重写一个新的脚本,以匹配用户期望的熟练程度。

3️⃣ 更好的文本到语音库?

当前项目仅使用了简单的 gTTS 库来合成语音,还有改进的空间。更先进的库提供了多语言支持、多说话者支持以及更自然的语音。比如:pyttsx3Amazon PollyIBM Watson TTSMicrosoft Azure Cognitive Services TTSCoqui.ai-TTS,以及 Meta 最近发布的Voicebox

4️⃣ 更多不同场景的测试?

由于时间限制,我只测试了几个场景,以确定聊天机器人是否能够生成有意义的对话。这些测试发现了我最初提示设计中的问题,提供了改进的机会。额外的场景测试可能会揭示被忽视的领域,并提出改进提示的方法。我已编制了一份全面的列表 ,包括典型的“对话”场景和“辩论”话题。随意尝试这些场景,并评估当前提示设计的表现。

5️⃣ 包含其他形式的生成型 AI?

这个项目主要探索了文本到文本(聊天机器人)和文本到语音的生成型 AI 技术。我们可以通过利用其他形式的生成型 AI,如文本到图像文本到视频,进一步提升用户体验。

  • 文本到图像:对于每个用户输入的场景,我们可以使用文本到图像模型来创建相应的图像。将这些图像与生成的对话一起展示,可以提供视觉上下文并增强语言学习的参与感。像StableDiffusionMidjourneyDALL-E这样的模型可以用于此目的。

  • 文本转视频:为了让应用更具多媒体功能,我们可以根据输入场景生成视频。像RunwayML这样的工具可以帮助实现这一点。此外,我们甚至可以尝试创建数字人来呈现对话,如果执行得当,这可能会大大提升用户体验。Synthesia可能是一个合适的工具。

6️⃣ 更多语言学习设置?

目前,我们的应用主要集中于“对话”和“辩论”学习模式。然而,增长潜力巨大。例如,我们可以引入其他学习模式,如“讲故事”和“文化学习”。此外,我们可以扩展聊天机器人的互动,以适应更多专业和技术场景。这些可能包括会议、谈判,或销售与市场、法律、工程等领域。这样的功能可能对那些希望提升专业语言能力的语言学习者有帮助。

6. 结论

哇,多么精彩的旅程!非常感谢你一直陪伴我 😃 从设计提示到创建聊天机器人,我们确实覆盖了很多领域。使用 LangChain 和 Streamlit,我们构建了一个功能齐全的双聊天机器人系统,可以用于语言学习,不错吧!

如果你觉得我的内容有用,可以通过这里买杯咖啡给我🤗 非常感谢你的支持!

建立一个能够识别我手写字的人工智能 — 第一部分

原文:towardsdatascience.com/building-an-ai-to-recognize-my-handwriting-part-i-7bef0d3cdc46

理论(和实践)的出发点

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Jonas Schröder

·发表于Towards Data Science ·12 分钟阅读·2023 年 4 月 2 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由作者提供

大约十年前,受到 Tim Ferriss 和其他自助书籍作者的启发,我开始定期在笔记本(纸质的那种)上手写。我现在已经填满了 10 到 15 本笔记本。把它们数字化岂不是很好吗?

本系列文章记录了我开发一个能够将我的手写笔记转换为正式纯文本文件的人工智能的过程。根据我的手写字的样子,这将确实非常具有挑战性。

这第一篇文章,第一部分,将涵盖基础知识。我将首先进一步解释我的动机,然后介绍理论框架,说明如何可以解决这个问题。

我将简要介绍卷积神经网络(CNNs),这是一种专门为图像识别设计的人工神经网络。之后,我将尝试一种自动化的方式来“识别”我的手写字,目的是避免手动标注和注释我的输入数据。

接下来的部分将更加实用,并实际使用 CNNs 与训练数据。但我认为这第一部分作为必要的基础是有用的,即使它以令人失望的结局告终。

像我许多的文章一样,我会在进展中发布,处理尚未知道的挑战,带领读者一起体验这个过程。

根据我收到的关于“数据科学家转量化交易”系列的反馈,我将将笔记本和文件上传到 GitHub以便更好地跟随。它们可以在这里找到(GitHub 链接),并将定期更新。

我希望你阅读这些内容时能像我创作时那样享受。随时欢迎联系我获取更多想法或问题,或者对这篇文章进行评论。

最好,

乔纳斯

我的动机:一堆个人笔记本

这十年来,我一直在做一种叫做“日记记录”的事情。与传统的“亲爱的日记”式写作不同,这种记录的目的是为了整理对各种事情的思考,而不是每天总结你的一天细节,这些细节通常在下周就变得无关紧要。比如:你现在的状况,你可能去哪里,以及最近你面临的挑战。或者是一般值得注意的经历。对我来说,它有双重目的:今天能够反思以及将思维过程归档以备未来参考

无论如何,我喜欢这样做,多年来我完成了大约 15 本笔记本。对我来说,它们非常宝贵,因为它们记录了我的生活,涵盖了担忧和挑战,以及亮点和改变人生的时刻。我想象着在一两十年后翻阅这些笔记本,充满了怀旧之情。因此,我想保留它们!

目前它们散落在德国的两个不同地方,这增加了在意外火灾中丢失一半的可能性。当然,更可能的威胁是时间,我们的老敌人。光盘在 25 年后会停止工作,而只有上帝知道我的纸质笔记能存活多久。我曾经找到过一些我在学校时写的旧文字。它们已经相当模糊了。

我考虑过将这些内容数字化一段时间了。肯定有服务提供商!然而,由于内容极其个人化,我不想与第三方分享。

作为一名专业的数据科学家,我知道可以建立和训练我自己的图像识别和 OCR 模型的可能性。我理论上知道该怎么做。但我从未做过。

此外,我知道有很多模型已经在手写文字上预训练过,并且我可以针对自己的数据集进行调整。当然,在这种情况下,局部运行它们不会被视为第三方。然而,再次根据我自己的笔迹判断,我很确定目前没有任何系统“足够智能”到能理解我写的内容。

长话短说,这就是我的动力。我的目标很简单:通过使用 AI 数字化我多年的工作,同时获取构建 OCR 系统的实际经验

我不想阅读太多关于其他人如何处理这个问题或“你应该做什么”的内容,因为这会妨碍我的学习体验。我预期会在某个时候失败,面临另一个需要解决的挑战。重复。

处理流程概述和使用的技术

现在我的动机已经明确,是时候考虑我们实际需要做什么了。简单来说,我期望有一个由三部分组成的流程:预处理、主要处理(CNN)和后处理。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者提供的图像

预处理

我需要我的手写图像数据,并以一种提高系统速度和性能指标的方式进行处理。我可以测试和实验不同的方式,例如不同的图像大小或通道数。我将主要使用OpenCV 和 Numpy来预处理数据。第二部分将介绍LabelImg,这是我用来创建标注输入数据的开源工具。

主要处理

这是魔法发生的地方,在这里,输入图像以浮点数矩阵的形式被转换为一个预测属于某一类别的概率向量。简而言之,输出结果可能类似于“image_1 是‘Test’,概率为 90%,‘Toast’,概率为 10%”。

我将使用各种卷积神经网络(CNNs),这是进行图像识别的首选架构。如果你对 CNNs 不太熟悉,我将在本文后面简要描述它们的主要属性。我不会使用任何预训练网络,依据我之前的动机,并假设世界上没有人有像我一样难看的手写字。

不过,我不会完全从头开始。我将定义并使用TensorFlowKeras来处理神经网络,以及它们所有可用的类和辅助函数。

后处理

此时我们将有一个训练好的 CNN,能够或多或少地识别我的手写字。然而,这一输出可能需要进一步清理和处理,使用各种 NLP 方法

例子:系统可能预测一个词为“Tost”,但这个词在德语中并不存在。流程中的另一个模型可能基于相似性将其纠正为“Test”。整个后处理部分在本文及下篇文章中不会涉及,因为我仍然离知道如何实现这一点很远。

关于我期望构建的三部分系统已经讲了很多。由于卷积神经网络(CNNs)在第一部分和第二部分中占据核心地位,我将以一种非常非科学、务实的方式简要介绍卷积神经网络(CNNs)。这个总结主要取自于Aurélien Géron 的《动手机器学习:使用 Scikit-Learn、Keras 和 TensorFlow(第 2 版)》,这是我最喜欢的实用机器学习入门书籍。

卷积神经网络(CNNs)简短介绍

如果你大致了解什么是人工神经网络(ANNs)及其在分类任务中的工作原理,你将能够很容易地理解接下来的内容。你会在本节末尾找到关于 CNN 的简短资源列表。

CNN 建立在 1950 年代末期关于我们大脑如何处理视觉输入的研究基础上。这些研究导致了1981 年诺贝尔奖。研究人员的主要发现是:许多神经元只对视觉场中小区域的视觉刺激做出反应。这些领域相互重叠,拼凑成我们所见的整体。此外,两个神经元可能共享相同的感受野,但一个只对水平线做出反应,另一个则对垂直线做出反应。

根据这些发现,计算机科学家开始创建专门为图像识别任务设计的神经网络。1998 年,Yann LeCun(现为 Meta 的首席 AI 科学家)创建了用于识别手写字符的LeNet-5架构。

那么,CNN 与其他(深度)神经网络有什么不同?本质上,CNN 与标准 ANN 类似,其中高级别的神经元从低级别的神经元输出中获取输入,以检测数据中的各种模式,随着数据在网络中传播,从简单到复杂。然而,CNN 有两个特殊的构建块,称为卷积层和池化层

这些构建块的动机很容易理解。以一个相对较小的图像 100px x 100px 为例。这意味着有 10,000 个输入(如果是彩色图像则为 30,000)。对于一个具有 1,000 个神经元的全连接标准 ANN,这将转化为 10,000,000 个连接需要适配。卷积层和池化层只允许部分连接这些层。此外,CNN 能够识别图像中出现的各种模式,而标准 ANN 则在处理偏移图像时会遇到困难。使用这些构建块有很多优点。现在了解更多关于它们的内容。

卷积层

根据上述研究人员的想法,卷积层中的神经元仅与其感受野中的像素相连(如果这是第一层),而不是与整个图像相连。在后续层中,神经元仅与小矩形中的输出相连。这是一个简单的想法,但仅用语言很难描述。下面的图像可能会有所帮助。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

由 Aphex34 — 自作,CC BY-SA 4.0,commons.wikimedia.org/w/index.php?curid=45679374

这个感受野矩形现在滑动(称为步幅)在图像上,每次输出一个值,从而在下一层减少图像的大小。结果是过滤器,也称为卷积。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者提供的图像

在训练过程中,CNN 将学习最有用的滤波器,如水平线与垂直线,这些可以被可视化。这些滤波器可能一开始非常简单,但随着数据在网络中进展,它们会被组合成越来越复杂的滤波器。应用于实际图像的滤波器被称为特征图(Feature Maps)(即滤波器和叠加图像的点积),突出显示激活滤波器的像素。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者提供的图像

池化层

为了进一步减少计算负担,所谓的池化层用于将输入的信息聚合到一个减少的输出中,作为下一个(卷积)层的输入。这个过程也被称为子采样。像卷积层一样,池化层具有有限的感受野,并在输入图像上滑动。然而,步幅通常设置为使得感受野不重叠。

例如,如今常用的最大池化层(Max Pooling Layers)输出其视野内所有神经元的最大值,从而只保留最相关的像素信息。下图可视化了这一点。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

由 Aphex34 创作,CC BY-SA 4.0,commons.wikimedia.org/w/index.php?curid=45673581

池化层可能非常具有破坏性,因为它们丢弃了 80-90%的信息。然而,它们也为数据添加了一些不变性,从而减少了对特定但不可泛化的细节的过拟合风险。

输出层

池化层通常跟随卷积层,这种模式重复几次,直到输出被展平(从矩阵到向量),以便得到与预期类别一样多的最终输出。例如,如果我们想要分类 0 到 9 的手写数字,我们会在最后使用一个具有 10 个输出的全连接层,以及一个 softmax 激活函数,如果我们想要预测图像属于十种可能性中的每一种的概率。

在输入“8”的图像之后的最终输出可能是向量[0.2,0,0,0,0,0,0.1,0,0.7,0],这意味着模型预测“8”的可能性最大,但也可能是“0”有 20%以及“6”有 10%的概率。根据训练图像,这些手写数字可能非常接近。

就这样,你所需要了解的全部内容就绪。CNNs 是一种用于图像识别的特殊人工神经网络。它们使用卷积层学习图像的简单和复杂模式,并使用池化层减少计算负担和过拟合的风险。

当然,CNNs(卷积神经网络)还有更多的内容,它们的输入数据的视觉性质使得它们在视觉上更容易理解。这里有一些进一步的基础资源,帮助你理解 CNNs 的工作原理。

维基百科:en.wikipedia.org/wiki/Convolutional_neural_network

Josh Starmer 的(幽默但 nonetheless 高度信息性的)QuestStats: www.youtube.com/watch?v=HGwBXDKFk9I

如果你仍然觉得不够,3Blue1Brown 的视频深入探讨了卷积是什么以及它们如何在各种应用中使用,例如图像处理(从 8:22 开始)。

开始使用我自己的手写文字

在概述了我们需要的技术及其理论工作方式后,现在是时候变得更实际,即开始编码了。你可以在 我的代码和文件这里 查看。

我开始时在纸上写了一封小信,拍了一张照片,并使用 OpenCV 在我的电脑上读取它。别在意它是德语的。电脑也不会在意(目前还不)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由作者提供

先暂时忽略我的实际任务,我在寻找一种自动检测纸张和墨水的方法,即检测文本。我的目标是找到一种以自动化的方式裁剪出单词的方法,而暂时忽略每个单词的实际含义。

我使用了所谓的行文本分割,通过调整我在这个 GitHub 笔记本 中找到的代码。简单来说,这个过程旨在首先识别文本行,然后遍历这些行以识别单词

它开始于对图像进行二值化,使每个像素可以是 0(黑色)或 1(白色)。类似于池化层的作用,下一步是膨胀,在这个步骤中,一个核(即接收域)在图像上滑动,将图像像素替换为该领域中的最大值,然后继续滑动。结果是图像的“生长”部分,因此命名为膨胀。

同样,与通过阅读理解相比,直接看到实际发生的情况更容易。左侧图像显示了我的信件在二值化后的样子,右侧则是经过膨胀处理后的样子。膨胀的效果类似于我们使用文本标记器时的效果。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由作者提供

从这一步到线检测只是一个小步骤。我将使用 OpenCV 的 findContours 函数。下方的蓝色框应该标识出我文本所写的行。正如你所见,这在某些部分效果更好。通过循环处理这些行以标记单个单词会生成带有黄色框的图像。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这看起来还不错,对吧?然而,它给了我 346 个识别出的单词(而实际上只有 58 个)。这种方法导致了重复,在我的图像中出现了相同的识别区域。即使在去除这些明显的重复之后,我仍然剩下 94 个单词。这些是单词的重叠部分,如下例所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由作者提供

现在我有了表示单词的信件片段,但大多数时候,我需要大量手动浏览样本以删除无意义的部分。此外,我还需要创建某种查找表,说明 image_00001.jpg 代表“ich”,而 image_00002.jpg 代表“Dokumente”。

总体而言,在效率方面并没有取得太大进展。我们可能更聪明了,但在实际应用方面尚未取得更大进展。

第一部分的总结与结论

我知道,我在这个系列的第一篇文章中以一个难题作为结尾。很抱歉!但通过将这个失败重新解读为挑战,我们将为更加乐观的第二部分奠定基础,我保证!

这段时间并没有浪费。我介绍了我们将用于此任务的核心技术——卷积神经网络(CNNs),它是如何工作的,以及这种网络架构与您之前可能了解的标准架构有何不同。了解你为何进入某个领域,而不仅仅是如何进入,是很重要的。因此,我概述了我的情况和动机。

目前的主要教训是: 如果我们想训练一个 CNN,我们需要正确标记的输入数据,不能依赖于自动生成这些数据的方法,例如使用稀释技术的行词分割方法在二值化输入图像上。

在第二部分中,我将开始训练 CNN 以识别上述信件中的单词。我会介绍 LabelImg,这是一款我用来标注的开源工具,以创建正确标记的我的手写训练数据集。

我们将看看这种非传统的 CNN 与 LeNet-5 和 VGGNet 等更著名的架构相比效果如何,以及通过调整数据预处理的参数,我们是否能提高准确性。

希望你读得愉快,并会继续关注。我已经可以说,第二部分也将以一个难题,即另一个挑战告终。好的一面是,将会有第三部分来(希望)解决它。

祝一切顺利,

乔纳斯

使用信号处理思想构建锻炼次数计数器

原文:towardsdatascience.com/building-an-exercise-rep-counter-using-ideas-from-signal-processing-fcdf14e76f81?source=collection_archive---------16-----------------------#2023-01-17

使用零交叉方法设计特定类别的计数器

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Aakash Agrawal

·

关注 发表在 Towards Data Science ·7 分钟阅读·2023 年 1 月 17 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由 Karsten Winegeart 在 Unsplash.com 提供

在这篇博客文章中,我讨论了一种非常新颖和独特的方法来构建实时锻炼次数计数器,这种方法在姿态估计的基础上应用了信号处理的思想。这种方法可以轻松地适应于构建其他类别的计数器。

从进行健身活动时计数某种运动的次数,到测量生物事件(如心跳和脉搏计数),重复计数有着无数的应用,近年来在这一领域的研究获得了大量关注。在这篇博客中,我讨论了使用信号处理领域的一些简单概念来构建一个快速而准确的重复计数器的方法。

我将首先迅速覆盖基础知识,然后介绍基于信号的重复计数公式。该方法的实现可以在这里找到。让我们从信号处理领域讨论一些可以用来构建重复计数器的概念开始。

零交叉

数学函数或波形穿越轴的交点的参考点(交点不一定是 0)。该术语通常用于电子学中,指的是周期性电压和电流中的没有信号的点。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图:零交叉。图片由作者提供。

峰值检测

在信号或波形中检测峰值(或位置),即观察到的突然偏离(你会看到尖峰)正常行为。检测这种偏差的技术是通过计算z-score,它捕捉信号的均值和标准差来计算偏差。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图:z-score 公式。图片由作者提供。

  1. 在信号的任何位置,z-score 算法本质上计算前一个数据点窗口的滞后平均值和滞后标准差。

  2. 通过计算范围 滞后平均值 +/- (阈值 * 滞后标准差); 来识别信号中的峰值;如果当前点的值超出了范围,则认为它是异常的一部分。

算法的更多细节和数学内容可以在这里找到。

重复计数 <> 信号处理

读者自然会产生一个问题,即零交叉和峰值检测算法如何用于重复计数。我们来看看:

假设

认为一个人/物体由一组关键点(关注点)组成。例如,这些关键点可以是肩膀、臀部等人体关节。

为了简化,我将问题限制为运动重复计数,因为人体关键点的可获得性较高(这一思路可以很容易地扩展到其他关键点易于获得的对象)。我们可以使用开源姿态估计模型来计算身体关键点的空间位置。我在这篇博客中使用了 Tensorflow 的Movenet姿态估计模型进行说明。这个模型相当快速和准确。

我们假设任何重复的运动,例如锻炼,都可以看作是关键点或函数(度量)在关键点上的一组正弦波形。这些度量包括不同身体关键点组合之间的角度和距离。

算法

基本思想是在实时移动的时间窗口中检测这些信号度量的零交叉点。

使用零交叉点进行重复计数是一个两阶段的过程:

阶段 1:参考计算

这个阶段是给定锻炼的一次性活动。我们首先使用参考视频找到一个零交叉线,也就是参考线(对于锻炼重复计数器,它可以是教练的视频)。大多数步骤将在重复计数阶段中使用。

a) 我们使用 Movenet 姿势估计模型实时观察人体关键点。请考虑以下参考:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图:使用 Movenet 模型进行身体关键点估计。教练正在做跳跃杰克。GIF 由作者提供。

b) 然后,我们使用不同身体关键点的组合计算度量。度量可以是关键点之间的距离或角度。一些度量示例:左肩到左掌的距离(欧几里得/y 轴)、左肩处的夹角等。

这个想法是使用能够覆盖广泛运动范围的度量。我通常更喜欢面对前置摄像头进行锻炼;因此,选择欧几里得距离和 y 轴距离度量即可。如果您希望为侧面锻炼建立重复计数器,您可能需要考虑 x 轴距离。我还通过肩膀到肩膀的距离来规范化度量,以便重复计数不会受到摄像头距离的影响。

c) 帧级姿势估计会导致身体关键点的抖动,从而导致计算度量的抖动。我们使用低通滤波器使度量平滑,并去除度量距离和角度中的抖动,这使得参考计算和重复计数更加准确。有关该技术的更多详细信息,请参见这里。确保在计算度量之前身体关键点在框架内。

d) 接下来,我们筛选出静止的度量信号。我们计算这些信号的标准差,并去除低于固定阈值的信号。如果没有度量被筛选出去,我们使用标准差最大的前 3 个度量。对于锻炼重复计数器,我们考虑总共18个度量。对于上述参考和标准差阈值为0.4的情况,我们最终得到8个对重复性贡献最大的度量。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图:度量波形。图片由作者提供。

e) 最后,我们将所有剩余的非平稳度量在时间上相加,并计算使用总和信号的均值作为参考线。我们将这些度量和参考线(均值)的 ID 保存到一个配置字典中,以便在重复计数时使用。教练视频的参考线:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图:参考视频的整体信号波形。图片来源:作者。

仔细查看参考视频可以看出,总共有 6 个重复。这些重复实际上对应于上面整体信号中观察到的峰值。

阶段 2:重复计数

这一阶段的大部分步骤与参考计算阶段是相同的。

a) 给定一个测试视频,我们首先实时计算关键点和归一化度量(与前一步相同)。

b) 我们使用参考计算阶段的配置字典来确定此练习所需的非平稳度量,然后将这些度量在时间上相加,创建一个综合的整体信号。

c) 我们实时创建一个固定大小的移动窗口,并检查它与参考线,即零交叉线交集。对于任何重复的动作,通常有两种状态,一种是运动的上升状态,另一种是下降状态,任意一种都是正常状态。

因此,对于一个重复动作,整体信号波形与参考线有两个交点。第一个交点表明该人已经达到动作的上升状态,第二个交点则表明该人回到正常状态,这个重复动作完成了。

就这样!

结果

让我们查看这种方法在测试视频上的表现。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图:使用零交叉技术进行的重复计数。GIF 来源:作者。

结果看起来不错,对吧?😎。这是上述测试视频的整体信号波形。直观地看,四个峰值对应于四个重复。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图:测试视频的整体信号波形。图片来源:作者。

方法的优点

  1. 这个算法相当快速准确

  2. 这个想法是直观的,实现起来很简单。

  3. 这种方法在生产环境中易于集成。

方法的缺点

  1. 不是一个通用的重复计数器(但这个想法可以适用于其他类别)。

  2. 需要使用每个练习/类别的参考视频来计算零交叉线,因此难以扩展到大量的练习数据。

  3. 在背景噪声较大的地方,姿态估计可能效果不好,从而导致重复计数结果不佳。

  4. 对于那些整体信号由于不同度量最终相互平均而变得平坦的练习,这可能不起作用。

在这篇博客中,我强调了使用零交叉点来计数重复次数的想法;然而,另一种技术——峰值检测,我们在开始时简要讨论过,也可以用来实时检测重复次数。

有用的参考资料

[1]. 使用低通滤波器使姿态估计更有效

[2]. 鲁棒的峰值检测算法(使用 z-分数)

[3]. MoveNet: 超快速且准确的姿态检测模型

[4]. 该方法的实现可以在这里找到;请阅读库中的说明以获取使用方法。

希望你能理解如何使用信号处理技术来构建一个特定类别的重复计数器。我很想了解阅读这篇博客的人的反馈。我很乐意回答有关上述概念的任何疑问/问题。欢迎反馈。你可以通过 Linkedin 联系我。

谢谢!

利用 GPTs 构建物理信息神经网络领域的专家 GPT

原文:towardsdatascience.com/building-an-expert-gpt-in-physics-informed-neural-networks-with-gpts-75ebf6925966

一个定制的副驾驶,用于简化 PINN 研究和开发

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Shuai Guo

·发表于Towards Data Science·14 分钟阅读·2023 年 11 月 18 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

定制 GPT 的标志。(由 DALL·E 3 生成)

在最近的 OpenAI DevDay 上,最令人兴奋的发布之一就是 GPTs。基本上,GPTs 是任何人都可以创建的用于特定目的的 ChatGPT 定制版本。配置一个可用的 GPT 的过程无需编程,只需通过聊天即可。因此,自发布以来,社区已经创建了各种 GPT,以帮助用户提高生产力,增添生活乐趣。

作为物理信息神经网络(PINN)领域的从业者,我经常使用 ChatGPT(GPT-4)来帮助我理解复杂的技术概念,调试在实现模型时遇到的问题,并提出新颖的研究想法或工程解决方案。尽管非常有用,我发现 ChatGPT 在提供超出其一般 PINN 知识的量身定制答案时常常显得力不从心。虽然我可以调整我的提示以纳入更多的上下文信息,但这是一项相当耗时的工作,有时会迅速消耗我的耐心。

现在可以轻松定制 ChatGPT,我想到一个想法:为什么不开发一个定制的 GPT,作为 PINN 专家🦸‍♀️,从我精心挑选的资源中汲取知识,并努力以量身定制的方式回答关于 PINN 的问题呢?

所以,在这篇博客文章中,让我们看看如何使这一目标成为现实!我们将首先介绍构建我们目标 GPT 的过程,提供指令设计和知识库的详细信息。然后,我们将进行一些演示,看看如何与新创建的 GPT 进行最佳互动。最后,我们将探讨未来发展的机会。

这个想法与你产生共鸣吗?让我们开始吧🗺️📍🚶‍♀️

这是我物理启发机器学习系列中的另一篇博客。其他包括:

物理启发神经网络:应用中心指南

揭开物理启发神经网络的设计模式

通过 PINN 和符号回归发现微分方程

通过物理启发的 DeepONet 进行操作学习

通过物理启发的 DeepONet 解决逆问题

随时查看它们!

内容目录

· 1. 如何构建?

∘ 知识

∘ 说明

· 2. 如何互动?

· 3. 如何扩展

· 4. 总结

1. 如何构建?

如前所述,构建定制化 GPT 非常简单:这只是将我们的想法传达给 GPT Builder 的问题。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

GPT Builder 环境。

为了开发我们的目标 GPT,我们需要特别关注知识和说明部分。让我们看看如何正确设置它们。

知识

本节允许我们向 GPT 附加文件。稍后,当 GPT 响应用户的问题时,它可能会从上传的文件中检索相关信息,并基于这些检索到的信息来回答问题。实质上,这些附加的文件作为知识库为定制化 GPT 提供支持,并促进 RAG(检索增强生成)模式。

为了为 GPT 提供正确的知识,我将我关于PINN 设计模式的系列技术博客上传到了 GPT Builder。以前,我在 Towards Data Science 上定期发表文章,提炼出可重用的解决方案,这些方案经过测试,已被证明对 PINN 实现中的常见问题有效。每篇文章都详细解释了一种设计模式,包括具体问题、相应解决方案的技术性、基准、优缺点以及替代方案。可以在这里找到一篇示例博客。

我保持这一系列文章的初衷是创建一个结构化的地图,供 PINN 从业者依赖,以便识别最适合特定挑战的技术,并跟上最新进展。现在我可以进一步推进,将系列文章整合到 GPT 的知识库中,使用户可以通过聊天直接学习 PINN 中的最佳实践。

指令

一旦 GPT 的知识更新完成,我们需要专注于制定正确的指令。指令部分允许我们输入命令来控制自定义 GPT 的行为。如果你有使用 Open API 的经验,指令就像是 Chat Completions API 中的“SystemMessage”。

对于我们当前的任务,我们希望创建一个在 PINN 领域的专家 GPT,并能够有效地帮助用户应对 PINN 研究和开发中的复杂性。我们将这些想法解释给 GPT 构建者,系统将自动生成一份指令草稿。

制定正确的指令通常是一个迭代过程,需要多轮解释思想 ==> 更新指令 ==> 测试 GPT 行为 ==> 完善思想。经过一段时间的调整,我得到了以下 GPT:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

生成的 GPT。(作者提供的图像)

指令(由 GPT 生成)

我是 PINN 设计模式专家,专注于物理信息神经网络,重点是系列技术文章中概述的设计模式,包括集成学习、主动学习、超参数调整、梯度增强学习、因果训练、协同点采样等主题。每篇文章讨论一个特定的设计模式,这些模式在研究论文中展示,涵盖以下方面:

  • 来源:提出设计模式的原始研究论文。

  • 问题:设计模式中的策略旨在解决的具体问题。

  • 解决方案:策略的关键组成部分、其实施方式以及其有效性的理由。

  • 基准:使用设计模式评估的偏微分方程及其相关性能。

  • 优势与劣势:策略有效的条件及其局限性。

  • 替代方案:其他类似问题的解决方法,提供对潜在解决方案的更广泛视角。

  • 潜在的未来改进:关于推进设计模式的建议。

我利用这种结构化的方法来帮助用户在多个方面,包括分析设计模式、评估解决方案、指导研究和开发,并提供量身定制的建议和解释以支持您的工作。

我的目标是促进对物理信息神经网络的全面而细致的理解,帮助用户在这一动态发展领域中导航并取得成功。

在我的回应中,我将整合来自综合数据库的物理信息神经网络知识和见解,确保用户体验流畅自然,而不会明确引用信息来源。然而,当用户明确询问信息来源时,我会指出哪个原始研究论文提出了相关的设计模式或策略。这种方法保持了沟通的专业性和流畅性,专注于根据物理信息神经网络的专业知识提供准确和相关的上下文信息。

这是一个非常全面的指令,涵盖了角色规范、知识库的描述,以及如何在与用户互动时使用该知识库。此外,我还为 GPT 启用了网页浏览功能,以便在必要时可以在线查找信息。

这里有一个附带说明:在开发自己的 GPT 并将其发布到公众时,你可能需要考虑隐私和网络安全问题。例如,具有不当目的的用户可能利用提示注入攻击来揭示原始的 GPT 配置指令,这些指令你可能不希望公开。在这些情况下,请记得添加额外的指令以防范这些攻击。

好了,现在我们已经构建了所需的 GPT,我们可以保存更改并将其发布到公众(我会在本文末尾分享 GPT 链接)。是时候测试一下并看看如何与之互动了。

2. 如何互动?

凭借对 PINN 最佳实践的特定知识,以及在预训练期间获得的一般 PINN 知识,新创建的 GPT 可以在多种不同方式上成为用户的有用助手。接下来,让我们看看一些具体的例子。

  • 提出具体的实施问题。

问:什么是 PINN 中的配点,我应该如何对其进行采样?

配点是 PINN 中的一个关键概念,以正确的方式进行采样对成功实现 PINN 至关重要。让我们看看定制的 GPT 如何回答这个问题:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

定制 GPT 生成的回应。 (图片由作者提供)

GPT 首先基于其对 PINN 的一般知识解释了配点的定义,然后提供了几种具体的、先进的采样策略(例如,RAD、RAR-D)的详细描述。这可能会很有帮助,因为它为从业者提供了快速的指引,便于深入探讨。它还表明,定制的 GPT 不仅能够从知识库中提取相关信息,而且知道何时这样做。

现在,如果我们向标准 ChatGPT(GPT-4)提出相同的问题,回答将如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

标准 ChatGPT(GPT-4)生成的回应。 (图片由作者提供)

我们可以看到标准的 ChatGPT 只能提供有关采样策略的一般信息。尽管它还建议将“自适应采样”作为潜在的策略之一,但其描述非常高层次,没有提供更多细节,例如如何调整采样,或如何测量网络性能等。此外,最后一个建议,即“结合数据与物理”,则相当无用,因为使用 PINN 的整个理念是将数据与物理结合。

  • 请求编写原型代码

问:你能用 Python 编写一个原型代码来演示 RAD 算法的工作流程吗?

继续之前的对话,我们可以进一步要求定制的 GPT 生成一些实现其建议的特定算法的原型代码,例如 RAD 算法。以下是回复:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

定制 GPT 生成的回复。(图像来源:作者)

不错!定制的 GPT 能够基于博客中的描述快速勾勒出一些原型代码。这对从业者了解算法的内部工作原理并实现快速原型设计,以查看该算法是否适合当前问题非常有用。

  • 请求最佳实践总结

问:你能总结一下那些可以有效提高 PINN 训练稳定性的方法吗?

这是从业者可能感兴趣的另一个常见点,即寻求与他们工作相关的量身定制的总结或概述。以下是定制 GPT 的回复:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

定制 GPT 生成的回复。(图像来源:作者)

我们可以看到定制的 GPT 能够生成广泛但具体的技术总结,从集成学习到超参数调优。回答与博客中所指出的内容非常一致,并反映了最先进的技术。同时,注意到博客系列还讨论了其他技术,如主动学习。然而,定制的 GPT 认为这些技术与“提高 PINN 训练的稳定性”并不十分相关,因此没有在回答中提及。总体而言,这是一个对从业者快速了解全貌的有用功能。

另一方面,如果我们问标准的 ChatGPT(GPT-4)相同的问题,得到的回答如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

标准 ChatGPT(GPT-4)生成的回复。为了节省空间,回复被截断。(图像来源:作者)

这里仅显示了完整响应的一部分以节省空间,但标准 GPT 的回答主要围绕神经网络训练的一般最佳实践,例如正则化、归一化与缩放、学习率调度、迁移学习和预训练等。这进一步显示了定制 GPT 具备针对我们需求的知识的好处。

  • 询问特定概念

问:因果训练在 PINN 训练中解决了什么问题?

对于新手从业者,GPT 的常见使用方式可能是更好地理解他们在研究论文中遇到的特定 PINN 概念。在这种情况下,我们要求 GPT 解释 因果训练 的含义,这是 2022 年引入到 PINN 的一个相当新的概念。以下是我们获得的响应:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

定制 GPT 生成的响应。(作者提供的图片)

在我提供给 GPT 的博客系列中,有一篇深入探讨了 PINN 训练中的因果关系问题。本质上,定制 GPT 抓住了这一点,并很好地总结了方法的核心思想。

  • 寻找原始研究论文

问:最初提出将因果训练引入 PINN 的论文是哪一篇?

如果某个具体技术对用户的问题确实很有趣,用户自然会想深入了解并阅读原始研究论文。因此,定制 GPT 的一个好特性是提供指向提出该技术的原始研究论文的指针。以下是获得的响应:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在这种情况下,定制 GPT 正确地指出了研究的来源。有趣的是,标准 GPT 则给出了完全错误的答案:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我在网上搜索过,没有找到由 Paris Perdikaris 撰写的《Causality-Inspired Neural Networks for Physics-Informed Machine Learning》这篇论文。这就是大型语言模型的幻觉!

  • 调试实际实施中的问题

问:当我在训练物理信息神经网络时,我注意到尽管训练损失在减少,但神经网络对物理量的预测始终不准确,尤其是在早期时间步骤。这可能是什么原因?

帮助调试实际实施问题可能是定制 GPT 最受从业者欢迎的功能之一。在这里,我们向定制 GPT 提出一个实际问题,并评估它是否能揭示可能的根本原因。获得的响应如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

定制 GPT 生成的响应片段。(作者提供的图片)

我们看到在众多可行的理由中,“时间因果关系的违反”排在首位。相反,如果我们向标准 GPT 提出同样的问题,我们的结果会有所不同:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

标准 GPT 生成的响应片段。(图像来源于作者)

我们看到建议的根本原因相当普遍,也适用于其他类型的神经网络,这些网络不一定是以物理为基础的。

定制 GPT 列出“时间因果性违反”作为首要原因的原因有两个:

  • 我的 PINN 系列博客中的每一篇都有一个部分专门描述特定技术旨在解决的问题。因此,该博客系列实际上是“症状”与“治疗”对的集合。

  • 一篇博客深入探讨了 PINN 中的因果训练概念。配备了这一知识库的定制 GPT 将“症状”(问题)与相应的“治疗”(将因果关系纳入训练)相匹配。

通过利用 PINN 中的症状与治疗的定制知识,定制 GPT 更有可能揭示具体实际实施问题的根本原因。

  • 激发新的研究想法

问:将主动学习应用于 PINN 的未来研究机会是什么?

最后,使用定制 GPT 的另一个用途是为新的研究方向和想法提供灵感。在这里,我们希望探索将主动学习技术与 PINN 相结合的可能性,我们的定制 GPT 提供了一个长长的潜在机会清单(为了节省一些空间,仅列出了机会标题):

========== * 以下列表由 GPT 生成 * ============

  1. 主动学习中的算法改进

  2. 高维问题的可扩展性

  3. 与其他机器学习技术的集成

  4. 实时与在线学习

  5. 不确定性量化

  6. 特定应用的主动学习策略

  7. 高效计算策略

  8. 逆问题中的主动学习

  9. 鲁棒性与泛化能力

  10. 与实验设计的集成

========== * 上述列表由 GPT 生成 * ============

对于其中一些方向,我已经看到最近的工作。对于其他方向,我不了解任何具体工作,它们可能非常有趣且富有成果!作为附注,GPT 提出的前两大方向绝对不是它的“原创”想法。它们实际上在我讨论主动学习应用于 PINN 的博客的“潜在未来改进”部分中明确提到。这表明定制 GPT 可以无缝地将其通用知识与检索到的特定信息结合起来,形成回答。

3. 如何扩展

我们已经讨论了专家 GPT 如何帮助从业者在 PINN 领域中导航。在这一部分,让我们换个角度,讨论一些未来可能的扩展方向。

  • 更新知识库:PINN 是一个充满活力的研究领域,时不时会宣布新的进展。因此,为了使专家 GPT 保持“专家”地位,定期更新其知识库并告知其关于 PINN 的最新进展至关重要。

  • 增加知识库的文档多样性:目前,知识库仅包含有关 PINN 最佳实践的文档。此外,我们可以添加其他类型的文档来丰富多样性。例如,添加 PINN 领域的综述论文可以使 GPT 为用户描绘更好的全貌;另外,添加面向应用的研究论文可以使 PINN 了解现实案例,从而更好地帮助用户完成任务。

  • 针对特定 PINN 库的编码助手:进行 PINN 研究的软件正在迅速发展。因此,跟上库中的最新进展对于从业者来说变得越来越困难。一个有前途的提高生产力的方法是设计一个 GPT 作为代码副驾驶,软件文档作为知识库。通过这种方式,编码助手 GPT 可以通过自然语言交流为用户的问题提供量身定制的编码解决方案。

  • 增强定制 GPT 与行动:我们尚未触及的定制 GPT 的另一项功能是所谓的“行动”。本质上,这些“行动”类似于“插件”,它们赋予 GPT 在 ChatGPT 之外采取行动的能力。一项近期的工作[1]探讨了利用 LLM 自动调用 API 来支持 PINN 软件以帮助用户完成任务的可能性。对于创建专家 GPT 的情况,我们也可以让专家 GPT 访问专业 PINN 软件的 API,以便它可以以自主的方式执行不同类型的分析。这可以大大降低从业者利用 PINN 的门槛,加速 PINN 技术在各种现实问题中的应用。

4. 总结

在本博客中,我们探讨了创建一个专注于 PINN 并可以帮助从业者日常工作的定制 GPT 的想法(使用 ChatGPT 最新的 GPT 功能)。我们解释了创建这个定制 GPT 的过程,并展示了它可能比标准 GPT 更有利的一些场景。这些场景包括:

  1. 询问具体实施问题。

  2. 请求编写原型代码

  3. 请求最佳实践总结

  4. 询问具体概念

  5. 寻找原始研究论文

  6. 调试实际实施中的问题

  7. 激发新的研究思路

最后,我们简要讨论了从用户体验角度进一步改进这个定制 GPT 的可能方式。

你可以在这里访问创建的 GPT:chat.openai.com/g/g-Z4YUXe3Bf-pinn-design-pattern-specialist

希望你觉得这个博客有用🤗如果你对学习更多关于 PINN 的内容感兴趣,请查看我之前的博客:

  • 解开物理信息神经网络设计模式的奥秘

  • 使用 PINN 和符号回归发现微分方程

  • 通过物理信息 DeepONet 进行算子学习

  • 通过物理信息 DeepONet 解决逆问题

或者,如果你想查看更多大型语言模型的应用:

  • 开发用于研究论文消化的自主双聊机器人系统

  • 当 AutoML 遇上大型语言模型

随时订阅我的新闻通讯或关注我的Medium

期待与你分享更多令人兴奋的项目。敬请关注!

参考文献

[1] Kumar 等人,《MyCrunchGPT: 基于 chatGPT 的科学机器学习框架》,arXiv,2023 年。

在 Panel 中构建交互式 ML 仪表板

原文:towardsdatascience.com/building-an-interactive-ml-dashboard-in-panel-d3e344ea7126

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Sophia Yang, Ph.D.

·发表于 Towards Data Science ·阅读时长 6 分钟·2023 年 6 月 6 日

作者:Andrew HuangSophia YangPhilipp Rudiger

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图像分类应用演示。

HoloViz Panel 是一个多功能的 Python 库,能够让开发人员和数据科学家轻松构建交互式可视化。无论你是在进行机器学习项目、开发 web 应用,还是设计数据仪表板,Panel 提供了一套强大的工具和功能,以增强你的数据探索和展示能力。在这篇博客文章中,我们将深入探讨 HoloViz Panel 的激动人心的功能,探索它如何彻底改变你的数据可视化工作流程,并演示如何用大约 100 行代码制作这样的应用。

尝试应用并查看代码:

充分利用 ML/AI 的力量

ML/AI 已成为数据分析和决策过程中的重要组成部分。借助 Panel,你可以将 ML 模型和结果无缝集成到你的可视化中。在这篇博客文章中,我们将探讨如何使用 OpenAI CLIP 模型进行图像分类任务。

CLIP 在大量的图像-文本对数据集上进行预训练,使其能够理解图像和相应的文本描述,并适用于各种下游任务,如图像分类。

我们使用了两个与 ML 相关的函数来执行图像分类任务。第一个函数load_processor_model使我们能够从 Hugging Face 加载预训练的 CLIP 模型。第二个函数get_similarity_score计算图像与提供的类别标签列表之间的相似度。

@pn.cache
def load_processor_model(
    processor_name: str, model_name: str
) -> Tuple[CLIPProcessor, CLIPModel]:
    processor = CLIPProcessor.from_pretrained(processor_name)
    model = CLIPModel.from_pretrained(model_name)
    return processor, model

def get_similarity_scores(class_items: List[str], image: Image) -> List[float]:
    processor, model = load_processor_model(
        "openai/clip-vit-base-patch32", "openai/clip-vit-base-patch32"
    )
    inputs = processor(
        text=class_items,
        images=[image],
        return_tensors="pt",  # pytorch tensors
    )
    outputs = model(**inputs)
    logits_per_image = outputs.logits_per_image
    class_likelihoods = logits_per_image.softmax(dim=1).detach().numpy()
    return class_likelihoods[0]py

为交互性绑定小部件

Panel 的一个关键优势是其将小部件绑定到函数的能力。这种功能为用户提供了一个直观的界面,以便操作底层数据并通过交互获得更深入的见解。

Python 函数

在我们的示例中,我们有一个process_input函数,它将从图像分类模型获得的相似度分数格式化为具有良好 UI 的 Panel 对象。实际函数利用了 async;如果你不熟悉 async,不用担心!我们将在后面的部分解释它,但请注意 async不是使用 Panel 的要求——Panel 只是支持它!

async def process_inputs(class_names: List[str], image_url: str):
    """
    High level function that takes in the user inputs and returns the
    classification results as panel objects.
    """
    ...
    yield results

面板小部件

我们使用了两个小部件来与此函数进行交互。

  1. image_url是一个 TextInput 小部件,允许输入任何字符串作为图像 URL。

  2. class_names是另一个 TextInput 小部件,它接受模型分类的可能类名。

image_url = pn.widgets.TextInput(
    name="Image URL to classify",
    value=pn.bind(random_url, randomize_url),
)
class_names = pn.widgets.TextInput(
    name="Comma separated class names",
    placeholder="Enter possible class names, e.g. cat, dog",
    value="cat, dog, parrot",
)

根据process_inputs函数签名,它接受两个参数:class_namesimage_url。我们可以使用pn.bind将每个参数/关键字参数绑定到一个小部件,如下所示:

interactive_result = pn.panel(
    pn.bind(process_inputs, image_url=image_url, class_names=class_names),
    height=600,
)
  • 第一个位置参数是函数名。

  • 关键字参数在匹配函数签名后,组件的值会绑定到函数的关键字参数上。

为了澄清,如果小部件命名为image_url_input而不是image_url,则调用将是:

pn.bind(process_inputs, image_url=image_url_input, ...)

添加模板设计样式

应用程序和仪表板的美观在吸引观众方面发挥了关键作用。Panel 使你能够根据流行的设计(如 Material 或 Fast)为你的可视化添加样式,使你能够创建视觉上吸引人且专业的界面。

在这个示例中,我们使用了一个bootstrap模板,我们可以控制在多个区域(如titlemain)显示的内容,并可以为各种组件指定尺寸和颜色:

pn.extension(design="bootstrap", sizing_mode="stretch_width")

我们还将Progress条设计设置为Material

row_bar = pn.indicators.Progress(
    ...
    design=pn.theme.Material,
)

注意,你也可以使用stylesstylesheets

计算密集型任务的缓存

一些数据处理任务可能计算成本高,导致性能缓慢。Panel 提供了缓存机制,使你可以存储昂贵计算的结果,并在需要时重用它们,从而显著提高应用程序的响应速度。

在我们的示例中,我们使用 pn.cache 装饰器缓存了 load_processor_model 的输出。这意味着我们不需要多次下载和加载模型。这一步骤将使你的应用程序感觉更加响应迅速!

附加说明:为了进一步响应性,还可以参考 defer_loading加载指示器

@pn.cache
def load_processor_model(
    processor_name: str, model_name: str
) -> Tuple[CLIPProcessor, CLIPModel]:
    processor = CLIPProcessor.from_pretrained(processor_name)
    model = CLIPModel.from_pretrained(model_name)
    return processor, model

使用 JavaScript 实现功能桥接

虽然 Panel 提供了丰富的互动功能,但你可能偶尔需要通过 JavaScript 实现额外的功能。将 JavaScript 代码与 Panel 可视化集成非常简单,从而扩展其功能。通过弥合 Python 和 JavaScript 之间的差距,你可以创建更高级的可视化效果,添加超出 Panel 原生功能范围的互动元素。

在我们应用程序的底部,你可能会看到一组图标,代表 Panel 的社交媒体账户,包括 LinkedIn 和 Twitter。当你点击这些图标中的任何一个时,你会被自动重定向到相应的社交媒体个人资料。这个无缝的点击和重定向功能是通过 Panel 的 JavaScript 集成 js_on_click 方法实现的:

footer_row = pn.Row(pn.Spacer(), align="center")
for icon, url in ICON_URLS.items():
    href_button = pn.widgets.Button(icon=icon, width=35, height=35)
    href_button.js_on_click(code=f"window.open('{url}')")
    footer_row.append(href_button)
footer_row.append(pn.Spacer())

理解同步与异步支持

异步编程因其高效处理并发任务的能力而受到欢迎。我们将讨论同步与异步执行的差异,并探索 Panel 对异步操作的支持。理解这些概念将使你能够在 Panel 中利用异步功能,提高应用程序的性能和响应性。

使用 async 使你的函数可以在单线程内进行协作多任务处理,并允许 IO 任务在后台进行。例如,当我们从互联网获取一张随机图片时,我们不知道需要等待多久,并且我们不希望在等待时停止程序。异步实现了并发执行,使我们在等待时可以执行其他任务,确保应用程序的响应性。记得添加相应的 await。

async def open_image_url(image_url: str) -> Image:
    async with aiohttp.ClientSession() as session:
        async with session.get(image_url) as resp:
            return Image.open(io.BytesIO(await resp.read()))

如果你对异步不熟悉,也可以将其改写为同步!异步不是使用 Panel 的必需条件!

def open_image_url(image_url: str) -> Image:
    with requests.get(image_url) as resp:
        return Image.open(io.BytesIO(resp.read()))

其他尝试的想法

在这里,我们仅探讨了一个想法;你可以尝试更多:

  • 互动文本生成:利用 Hugging Face 强大的语言模型,如 GPT 或 Transformer,生成互动文本。结合 Panel 的小部件绑定功能与 Hugging Face 模型,创建动态界面,让用户输入提示或调整参数以生成自定义文本输出。

  • 情感分析和文本分类:使用 Hugging Face 的预训练情感分析或文本分类模型构建互动仪表盘。使用 Panel,用户可以输入文本样本,展示预测的情感或类别概率,并通过互动可视化探索模型预测。

  • 语言翻译:利用 Hugging Face 的翻译模型创建互动语言翻译界面。使用 Panel,用户可以输入一种语言的文本并可视化翻译后的输出,方便实验和探索翻译质量。

  • 命名实体识别(NER):将 Hugging Face 的 NER 模型与 Panel 结合,构建互动 NER 可视化。用户可以输入文本并可视化识别的实体,突出实体范围,并通过直观界面探索模型预测。

  • 聊天机器人和对话 AI:使用 Hugging Face 的对话模型,你可以创建互动聊天机器人或对话代理。Panel 使用户能够与聊天机器人进行互动对话,展示响应,并通过互动小部件自定义聊天机器人的行为。

  • 模型微调和评估:使用 Panel 创建互动界面,以微调和评估 Hugging Face 模型。用户可以输入自定义训练数据,调整超参数,展示训练进展,并通过互动可视化评估模型性能。

  • 模型比较和基准测试:使用 Panel 构建互动界面,以比较和基准测试不同 Hugging Face 模型在特定 NLP 任务中的表现。用户可以输入样本数据,比较模型预测,展示性能指标,并探索不同模型之间的权衡。

查看我们的应用程序画廊以获取其他创意!祝实验愉快!

加入我们的社区

Panel 社区充满活力和支持,经验丰富的开发者和数据科学家乐于帮助和分享他们的知识。加入我们并与我们联系:

最初发布于 https://blog.holoviz.org

作者 Andrew HuangSophia YangPhilipp Rudiger

Sophia Yang 是高级数据科学家。通过 LinkedInTwitterYouTube 与我联系,并加入 DS/ML 书籍俱乐部 ❤️

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值