整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

javaScript 函数形参与实参

javaScript 函数形参与实参

函数名后面的括号中的内容是一种变量,这个变量叫做参数

参数是指由外部传入到函数中的变量,仅作为变量使用,但是该变量可以是任何内容,包括函数。被传入的参数作为私有变量使用,可以被覆盖掉。外部传入的参数可以节省全局变量的定义,甚至保证函数中的部分变量的独立性。

1、参数名起名规则和变量名类似,但是有时候可以使用下划线来起头

2、如果有多个参数时,就需要使用逗号分隔

形参:一个接收实参的变量

function abc(n,m){
            console.log(n,m);
        }

上述代码中n、m为形参,这两个变量的范围是仅在当前函数语句块中,在函数外不能调用形参。

实参:真实的数值、字符串

abc(5,6);

在调用函数时,传入指定的参数为实参,这里5,6为实参。参数传值是按照顺序复赋值的,不能颠倒。

不填入参数也可以执行,但是这种方式就相当于给形参定义值为undefined 。如abc();

如果只填入一个值,就表示第一个赋值10,第二个仍然赋值undefined 。如abc(10).

如果传入多值,多传入的参数不会被接受,如abc(5,6,7),这里7是不会被调用的。

代码进行单元测试是几乎每个软件工程师都要完成的工作。本文以C++语言为基础,讲解如何进行单元测试并生成测试报告。

前言

测试是软件开发过程中一个必须的环节,测试确保软件的质量符合预期。

对于工程师自己来说,单元测试也是提升自信心的一种方式。

直接交付没有经过测试的代码是不太好的,因为这很可能会浪费整个团队的时间,在一些原本早期就可以发现的问题上。而单元测试,就是发现问题一个很重要的环节。

本文以C++语言为基础,讲解如何进行单元测试并生成测试报告。

在工具上,我们会使用下面这些:

  • GCC
  • CMake
  • Google Test
  • gcov
  • lcov

演示项目

为了方便本文的讲解,我专门编写了一个演示项目作为代码示例。

演示项目的源码可以在我的Github上获取:paulQuei/gtest-and-coverage。

你可以通过下面几条命令下载和运行这个项目:

git clone https://github.com/paulQuei/gtest-and-coverage.git
cd gtest-and-coverage
./make_all.sh

要运行这个项目,你的机器上必须先安装好前面提到的工具。如果没有,请阅读下文以了解如何安装它们。

如果你使用的是Mac系统,下文假设你的系统上已经安装了brew包管理器。如果没有,请通过下面这条命令安装它:

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

项目结构

演示项目的目录结构如下:

.
├── CMakeLists.txt
├── googletest-release-1.8.1.zip
├── include
│   └── utility.h
├── make_all.sh
├── src
│   └── utility.cpp
└── test
    └── unit_test.cpp

这里演示的内容是:以测试一个我们要提供的软件库为例,讲解如何对其进行单元测试并生成测试报告。

为了简单起见,这个软件库只有一个头文件和一个实现文件。

当然,在实际上的项目中,一个软件库会通常包含更多的文件,不过这并不影响我们要说明的问题。

演示项目中的文件说明如下:

文件名称说明make_all.sh入口文件,会执行:编译,测试和生成报告等所有工作CMakeLists.txt项目的编译文件googletest-release-1.8.1.zipgoogle test源码压缩包utility.h待测试的软件库的头文件utility.cpp待测试的软件库的实现文件unit_test.cpp对软件库进行单元测试的代码

测试环境

演示项目在如下的环境中测试过。

  • MacBook Pro操作系统:macOS Mojave 10.14.1编译器:Apple LLVM version 10.0.0 (clang-1000.11.45.2)CMake:cmake version 3.12.1Google Test: 1.8.1lcov: lcov version 1.13
  • Ubuntu操作系统:Ubuntu 16.04.5 LTS编译器:gcc (Ubuntu 5.4.0-6ubuntu1~16.04.10) 5.4.0 20160609CMake:cmake version 3.5.1Google Test:1.8.1lcov:lcov version 1.12

关于CMake

为了简化编译的过程,这里使用CMake作为编译工具。关于CMake的更多内容请参见请官网:https://cmake.org。

关于如何安装CMake请参见这里:Installing CMake。

另外,你也可以通过一条简单的命令来安装CMake:

Mac系统:

brew install cmake

Ubuntu系统

sudo apt install cmake

由于篇幅所限,这里不打算对CMake做过多讲解,读者可以访问其官网或者在网络上搜寻其使用方法。

这里仅仅对演示项目中用到的内容做一下说明。演示项目中的CMakeLists.txt内容如下:

cmake_minimum_required(VERSION 2.8.11) ①
project(utility) ②

set(CMAKE_CXX_STANDARD 11) ③

set(GTEST googletest-release-1.8.1) ④
include_directories("./include" "${GTEST}/googletest/include/")
link_directories("build/gtest/googlemock/gtest/")

SET(CMAKE_CXX_FLAGS  "${CMAKE_CXX_FLAGS} --coverage") ⑤

add_library(${CMAKE_PROJECT_NAME}_lib src/utility.cpp) ⑥

add_executable(unit_test test/unit_test.cpp) ⑦
target_link_libraries(unit_test ${CMAKE_PROJECT_NAME}_lib gtest gtest_main pthread) ⑧

以编号为序,这段代码说明如下:

  1. 设置使用的CMake最低版本号为2.8.11。
  2. 指定项目的名称为”utility”,项目名称可以通过${CMAKE_PROJECT_NAME}进行引用。
  3. 指定使用C++11。
  4. 这里的三行是编译google test,并将其头文件路径和编译结果的库文件路径添加到环境中。因为后面在编译单元测试代码的时候需要用到。
  5. 添加--coverage到编译器flag中,这个参数是很重要的,因为这是生成代码覆盖率所必须的。关于该编译参数的说明见这里:Program Instrumentation Options。
  6. 编译我们的软件库,这里将生成libutility_lib.a库文件。
  7. 编译单元测试的可执行文件。
  8. 单元测试的可执行文件需要链接我们开发的软件库以及google test的库。另外,google test依赖了pthread,所以这个库也需要。

关于测试

软件测试有很多种分类方式。从测试的级别来说,可以大致分为:

  • 单元测试
  • 集成测试
  • 系统测试

这其中,单元测试是最局部和具体的。它通常需要对代码中的每一个类和函数进行测试。

单元测试通常由开发者完成,需要针对代码逻辑进行测试。所以它是一种白盒测试。

关于xUnit

xUnit是几种单元测试框架的总称。最早源于Smalltalk的单元测试框架SUnit,它是由Kent Beck开发的。

除此之外,还有针对Java语言的JUnit,针对R语言的RUnit。

在本文中,我们使用Google开发的xUnit框架:Google Test。

Google Test介绍

Google Test的项目主页在Github上:Github: Google Test。

实际上,这个项目中同时包含了GoogleTest和GoogleMock两个工具,本文中我们只会讲解第一个。

Google Test支持的操作系统包含下面这些:

  • Linux
  • Mac OS X
  • Windows
  • Cygwin
  • MinGW
  • Windows Mobile
  • Symbian

目前有很多的项目都使用了Google Test,例如下面这些:

  • Chromium projects
  • LLVM
  • Protocol Buffers
  • OpenCV
  • tiny-dnn

编译Google Test

关于如何编译Google Test请参见这里:Generic Build Instructions。

为了便于读者使用,我们在演示项目中包含了Google Test 1.8.1的源码压缩包。并且在CMake文件中,同时包含了Google Test的编译和使用配置工作。

如果使用演示项目,读者将不需要手动处理Google Test的编译和安装工作。

使用Google Test

演示项目代码说明

为了便于下文说明,演示项目中包含了几个简单的函数。

可以从这里下载源码以便查看其中的内容:paulQuei/gtest-and-coverage。

演示项目中的软件库包含一个头文件和一个实现文件。头文件内容如下:

// utility.h

#ifndef INCLUDE_UTILITY_
#define INCLUDE_UTILITY_

enum CalcType {
    ADD,
    MINUS,
    MULTIPLE,
    DIVIDE
};

class Utility {
public:
    int ArithmeticCalculation(CalcType op, int a, int b);

    double ArithmeticCalculation(CalcType op, double a, double b);

    bool IsLeapYear(int year);
};

#endif

这个头文件说明如下:

  • 头文件包含了三个函数,前两个用来做int和double类型的四则运算。最后一个判断输入的年份是否是闰年。
  • 当然,在实际的工程中,前两个函数合并实现为一个泛型函数更为合适。但这里之所以分成两个,是为了查看代码覆盖率所用。
  • 关于闰年说明如下:能被4整除但不能被100整除的年份为普通闰年。能被100整除,也同时能被400整除的为世纪闰年。其他都不是闰年。例如:1997年不是闰年,2000年是闰年,2016年是闰年,2100不是闰年。

这三个函数的实现也不复杂:

// utility.cpp

#include "utility.h"

#include <iostream>
#include <limits>

using namespace std;

int Utility::ArithmeticCalculation(CalcType op, int a, int b) {
    if (op==ADD) {
        return a + b;
    } else if (op==MINUS) {
        return a - b;
    } else if (op==MULTIPLE) {
        return a * b;
    } else {
        if (b==0) {
            cout << "CANNO Divided by 0" << endl;
            return std::numeric_limits<int>::max();
        }
        return a / b;
    }
}

double Utility::ArithmeticCalculation(CalcType op, double a, double b) {
    if (op==ADD) {
        return a + b;
    } else if (op==MINUS) {
        return a - b;
    } else if (op==MULTIPLE) {
        return a * b;
    } else {
        if (b==0) {
            cout << "CANNO Divided by 0" << endl;
            return std::numeric_limits<double>::max();
        }
        return a / b;
    }
}

bool Utility::IsLeapYear(int year) {
    if (year % 100==0 && year % 400==0) {
        return true;
    }
    if (year % 100 !=0 && year % 4==0) {
        return true;
    }
    return false;
}

开始测试

接下来我们就要对上面这些代码进行测试了。

要使用Google Test进行测试,整个过程也非常的简单。只要进行下面三部:

  1. 创建一个测试用的cpp文件
  2. 为上面这个测试用的cpp文件编写Makefile(或者CMake文件)。同时链接:待测试的软件库gtest库gtest_main库pthread库(Google Test使用了这个库所以需要)
  3. 编写测试代码,编译并运行测试的可执行程序。

并且,测试代码写起来也非常的简单,像下面这样:

#include "utility.h"

#include "gtest/gtest.h"

TEST(TestCalculationInt, ArithmeticCalculationInt) {
    Utility util;
    EXPECT_EQ(util.ArithmeticCalculation(ADD, 1, 1), 2);
    EXPECT_EQ(util.ArithmeticCalculation(MINUS, 2, 1), 1);
    EXPECT_EQ(util.ArithmeticCalculation(MULTIPLE, 3, 3), 9);
    EXPECT_EQ(util.ArithmeticCalculation(DIVIDE, 10, 2), 5);
    EXPECT_GT(util.ArithmeticCalculation(DIVIDE, 10, 0), 999999999);
}

是的,就是这么简单的几行代码,就对整数四则运算的函数进行了测试。

TEST后面所包含的内容称之为一条case,通常我们会为每个函数创建一个独立的case来进行测试。一个测试文件中可以包含很多条case。同时,一条case中会包含很多的判断(例如EXPECT_EQ...)。

注意:在做单元测试的时候,保证每条case是独立的,case之间没有前后依赖关系是非常重要的。

当然,测试代码中包含的判断的多少将影响测试结果的覆盖率。所以在编写每条case的时候,我们需要仔细思考待测试函数的可能性,有针对性的进行测试代码的编写。

这段代码应该很好理解,它分别进行了下面这些测试:

  • 1 + 1=2
  • 2 – 1=1
  • 3 x 3=9
  • 10 / 2=5
  • 10 / 0 > 999999999

你可能会发现,这段代码里面甚至没有main函数。它也依然可以生成一个可执行文件。这就是我们链接gtest_main所起的作用。

在实际的测试过程中,你想判断的情况可能不止上面这么简单。下面我们来看看Google Test还能做哪些测试。

测试判断

Google Test对于结果的判断,有两种形式:

  • ASSERT_*:这类判断是Fatal的。一旦这个判断出错,则直接从测试函数中返回,不会再继续后面的测试。
  • EXPECT_*:这类判断是Nonfatal的。它的效果是,如果某个判断出错,则输出一个错误信息,但是接下来仍然会继续执行后面的测试。

可以进行的判断方法主要有下面这些:

布尔判断

FatalNonfatal说明ASSERT_TRUE(condition)EXPECT_TRUE(condition)判断 condition 为 trueASSERT_FALSE(condition)EXPECT_FALSE(condition)判断 condition 为 false

二进制判断

FatalNonfatal说明ASSERT_EQ(expected, actual)EXPECT_EQ(expected, actual)判断两个数值相等ASSERT_NE(val1, val2)EXPECT_NE(val1, val2)val1 !=val2ASSERT_LT(val1, val2)EXPECT_LT(val1, val2)val1 < val2ASSERT_LE(val1, val2)EXPECT_LE(val1, val2)val1 <=val2ASSERT_GT(val1, val2)EXPECT_GT(val1, val2)val1 > val2ASSERT_GE(val1, val2)EXPECT_GE(val1, val2)val1 >=val2

说明:

  • EQ:EQual
  • NE:Not Equal
  • LT:Less Than
  • LE:Less Equal
  • GT:Greater Than
  • GE:Greater Equal

字符串判断

FatalNonfatal说明ASSERT_STREQ(expected, actual)EXPECT_STREQ(expected, actual)两个C string相同ASSERT_STRNE(str1, str2)EXPECT_STRNE(str1, str2)两个C string不相同ASSERT_STRCASEEQ(exp, act)EXPECT_STRCASEEQ(exp, act)忽略大小写,两个C string相同ASSERT_STRCASENE(str1, str2)EXPECT_STRCASENE(str1, str2)忽略大小写,两个C string不相同

浮点数判断

FatalNonfatal说明ASSERT_FLOAT_EQ(exp, act)EXPECT_FLOAT_EQ(exp, act)两个float数值相等ASSERT_DOUBLE_EQ(exp, act)EXPECT_DOUBLE_EQ(exp, act)两个double数值相等ASSERT_NEAR(val1, val2, abs_err)EXPECT_NEAR(val1, val2, abs_err)val1和val2的差距不超过abs_err

异常判断

FatalNonfatal说明ASSERT_THROW(stmt, exc_type)EXPECT_THROW(stmt, exc_type)stmt抛出了exc_type类型的异常ASSERT_ANY_THROW(stmt)EXPECT_ANY_THROW(stmt)stmt抛出了任意类型的异常ASSERT_NO_THROW(stmt)EXPECT_NO_THROW(stmt)stmt没有抛出异常

Test Fixture

在某些情况下,我们可能希望多条测试case使用相同的测试数据。例如,我们的演示项目中,每条case都会需要创建Utility对象。

有些时候,我们要测试的对象可能很大,或者创建的过程非常的慢。这时,如果每条case反复创建这个对象就显得浪费资源和时间了。此时,我们可以使用Test Fixture来共享测试的对象。

要使用Test Fixture我们需要创建一个类继承自Google Test中的::testing::Test。

还记得我们前面说过,我们要尽可能的保证每条测试case是互相独立的。但是,当我们在多条case之间共享有状态的对象时,就可能出现问题。

例如,我们要测试的是一个队列数据结构。有的case会向队列中添加数据,有的case会从队列中删除数据。case执行的顺序不同,则会导致Queue中的数据不一样,这就可能会影响case的结果。

为了保证每条case是独立的,我们可以在每条case的执行前后分别完成准备工作和清理工作,例如,准备工作是向队列中添加三个数据,而清理工作是将队列置空。

这两项重复性的工作可以由::testing::Test类中的Setup和TearDown两个函数来完成。

我们演示用的Utility类是无状态的,所以不存在这个问题。因此,这里我们仅仅在Setup和TearDown两个函数中打印了一句日志。

使用Test Fixture后,我们的代码如下所示:

class UtilityTest : public ::testing::Test {

protected:

void SetUp() override {
    cout << "SetUp runs before each case." << endl;
}

void TearDown() override {
    cout << "TearDown runs after each case." << endl;
}

Utility util;

};

这段代码说明如下:

  1. Setup和TearDown两个函数标记了override以确认是重写父类中的方法,这是C++11新增的语法。
  2. 我们的Utility类是无状态的,因此Setup和TearDown两个函数中我们仅仅打印日志以便确认。
  3. 将Utility util设置为protected以便测试代码中可以访问。(从实现上来说,测试case的代码是从这个类继承的子类,当然,这个关系是由Google Test工具完成的)。

要使用这里定义的Test Fixture,测试case的代码需要将开头的TEST变更为TEST_F。

这里_F就是Fixture的意思。

使用TEST_F的case的代码结构如下:

TEST_F(TestCaseName, TestName) {
  ... test body ...
}

这里的TestCaseName必须是Test Fixture的类名。

所以我们的测试代码写起来是这样:

TEST_F(UtilityTest, ArithmeticCalculationDouble) {
    EXPECT_EQ(util.ArithmeticCalculation(ADD, 1.1, 1.1), 2.2);
}

TEST_F(UtilityTest, ArithmeticCalculationIsLeapYear) {
    EXPECT_FALSE(util.IsLeapYear(1997));
    EXPECT_TRUE(util.IsLeapYear(2000));
    EXPECT_TRUE(util.IsLeapYear(2016));
    EXPECT_FALSE(util.IsLeapYear(2100));
}

我们针对ArithmeticCalculation方法故意只进行了一种情况的测试。这是为了最终生成代码覆盖率所用。

运行测试

编写完单元测试之后,再执行编译工作便可以运行测试程序以查看测试结果了。

测试的结果像下面这样:

如果测试中包含了失败的case,则会以红色的形式输出。同时,会看到失败的case所处的源码行数,这样可以很方便的知道哪一个测试失败了,像下面这样:

只想有选择性的跑部分case,可以通过--gtest_filter参数进行过滤,这个参数支持*通配符。

像下面这样:

$ ./build/unit_test --gtest_filter=*ArithmeticCalculationInt
Running main() from googletest/src/gtest_main.cc
Note: Google Test filter=*ArithmeticCalculationInt
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from TestCalculationInt
[ RUN      ] TestCalculationInt.ArithmeticCalculationInt
CANNO Divided by 0
[       OK ] TestCalculationInt.ArithmeticCalculationInt (0 ms)
[----------] 1 test from TestCalculationInt (0 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (0 ms total)
[  PASSED  ] 1 test.

如果想要更好的理解这些内容。请读者下载演示项目之后完成下面这些操作:

在utility.h和utility.cpp中添加一些新的函数。在新添加的函数中故意包含一个bug。为新添加的函数编写测试代码,并测试出函数中包含的bug。

代码覆盖率

在进行单元测试之后,我们当然希望能够直观的看到我们的测试都覆盖了哪些代码。

理论上,如果我们能做到100%的覆盖我们的所有代码,则可以说我们的代码是没有Bug的。

但实际上,100%的覆盖率要比想象得困难。对于大型项目来说,能够达到80% ~ 90%的语句覆盖率就已经很不错了。

覆盖率的类型

先来看一下,当我们在说“覆盖率”的时候我们到底是指的什么。

实际上,代码覆盖率有下面几种类型:

  • 函数覆盖率:描述有多少比例的函数经过了测试。
  • 语句覆盖率:描述有多少比例的语句经过了测试。
  • 分支覆盖率:描述有多少比例的分支(例如:if-else,case语句)经过了测试。
  • 条件覆盖率:描述有多少比例的可能性经过了测试。

这其中,函数覆盖率最为简单,就不做说明了。

语句覆盖率是我们最常用的。因为它很直观的对应到我们写的每一行代码。

而分支覆盖率和条件覆盖率可能不太好理解,需要做一下说明。

以下面这个C语言函数为例:

int foo (int x, int y) {
    int z=0;
    if ((x > 0) && (y > 0)) {
        z=x;
    }
    return z;
}

这个函数中包含了一个if语句,因此if语句成立或者不成立构成了两个分支。所以如果只测试了if成立或者不成立的其中之一,其分支覆盖率只有 1/2=50%。

而条件覆盖率需要考虑每种可能性的情况。

对于if (a && b)这样的语句,其一共有四种可能的情况:

  1. a=true, b=true
  2. a=true, b=false
  3. a=false, b=true
  4. a=false, b=false

请读者思考一下:对于三层if嵌套,每个if语句包含三个布尔变量的代码,如果要做到100%的条件覆盖率,一共要测试多少种情况。

很显示,在编写代码的时候,尽可能的减少代码嵌套,并且简化逻辑运算是一项很好的习惯。

便于测试的代码也是便于理解和维护的,反之则反。

有了这些概念之后,我们就可以看懂测试报告中的覆盖率了。

gcov

gcov是由GCC工具链提供的代码覆盖率生成工具。它可以很方便的和GCC编译器配合使用。

通常情况下,安装好GCC工具链,也就同时包含了gcov命令行工具。

对于代码覆盖率工具所做的工作,可以简单的理解为:标记一次运行过程中,哪些代码被执行过,哪些没有执行。

因此,即便没有测试代码,直接运行编译产物也可以得到代码的覆盖率。只不过,通常情况下这样得到的覆盖率较低罢了。

使用

这里我们以另外一个简单的代码示例来说明gcov的使用。

这段代码如下:

// test.c

#include <stdio.h>

int main (void) {

  for (int i=1; i < 10; i++) {
      if (i % 3==0)
        printf ("%d is divisible by 3\n", i);
      if (i % 11==0)
        printf ("%d is divisible by 11\n", i);
  }

  return 0;
}

这是一个仅仅包含了main函数的c语言代码,main函数的逻辑也很简单。

我们将这段代码保存到文件test.c。

要通过gcov生成代码覆盖率。需要在编译时,增加参数--coverage:

gcc --coverage test.c

--coverage等同于编译参数-fprofile-arcs -ftest-coverage以及在链接时增加-lgcov。

此处的编译结果除了得到可执行文件a.out,还会得到一个test.gcno文件。该文件包含了代码与行号的信息,在生成覆盖率时会需要这个文件。

很显然,带--coverage编译参数得到的编译产物会比不带这个参数要包含更多的信息,因此编译产物会更大。所以这个参数只适合在需要生成代码覆盖率的时候才加上。对于正式发布的编译产物,不应该添加这个编译参数。

当我们执行上面编译出来的可执行文件a.out时,我们还会得到每个源码文件对应的gcda后缀的文件。由test.gcno和test.gcda这两个文件,便可以得到代码的覆盖率结果了。

关于这两个文件的说明请参见这里:Brief description of gcov data files

只需要通过gcov指定源文件的名称(不需要带后缀):gcov test,便可以得到包含覆盖率的结果文件 test.c.gcov了。

回顾一下我们刚刚的操作内容:

$ gcc --coverage test.c
$ ll
total 72
-rwxr-xr-x  1 Paul  staff    26K 11 10 14:41 a.out
-rw-r--r--  1 Paul  staff   240B 11 10 14:41 test.c
-rw-r--r--  1 Paul  staff   720B 11 10 14:41 test.gcno
$ ./a.out 
3 is divisible by 3
6 is divisible by 3
9 is divisible by 3
$ ll
total 80
-rwxr-xr-x  1 Paul  staff    26K 11 10 14:41 a.out
-rw-r--r--  1 Paul  staff   240B 11 10 14:41 test.c
-rw-r--r--  1 Paul  staff   212B 11 10 14:42 test.gcda
-rw-r--r--  1 Paul  staff   720B 11 10 14:41 test.gcno
$ gcov test
File 'test.c'
Lines executed:85.71% of 7
test.c:creating 'test.c.gcov'

$ ll
total 88
-rwxr-xr-x  1 Paul  staff    26K 11 10 14:41 a.out
-rw-r--r--  1 Paul  staff   240B 11 10 14:41 test.c
-rw-r--r--  1 Paul  staff   623B 11 10 14:42 test.c.gcov
-rw-r--r--  1 Paul  staff   212B 11 10 14:42 test.gcda
-rw-r--r--  1 Paul  staff   720B 11 10 14:41 test.gcno

我们可以cat test.c.gcov一下,查看覆盖率的结果:

        -:    0:Source:test.c
        -:    0:Graph:test.gcno
        -:    0:Data:test.gcda
        -:    0:Runs:1
        -:    0:Programs:1
        -:    1:// test.c
        -:    2:
        -:    3:#include <stdio.h>
        -:    4:
        -:    5:int main (void) {
        -:    6:
       20:    7:  for (int i=1; i < 10; i++) {
        9:    8:      if (i % 3==0)
        3:    9:        printf ("%d is divisible by 3\n", i);
        9:   10:      if (i % 11==0)
    #####:   11:        printf ("%d is divisible by 11\n", i);
        9:   12:  }
        -:   13:
        1:   14:  return 0;
        -:   15:}

这个结果应该还是很容易理解的,最左边一列描述了代码的覆盖情况:

  • -: 表示该行代码被覆盖了
  • 整数: 表示被执行的次数
  • #####:表示该行没有被覆盖

lcov

gcov得到的结果是本文形式的。但很多时候,我们可能希望得到更加美观和便于浏览的结果。

此时就可以使用lcov了。

lcov是gcov工具的图形前端。它收集多个源文件的gcov数据,并生成描述覆盖率的HTML页面。生成的结果中会包含概述页面,以方便浏览。

lcov支持我们前面提到的所有四种覆盖率。

这个链接是lcov生成的报告样例:lcov – code coverage report。

安装

lcov并非包含在GCC中,因此需要单独安装。

Mac系统

brew install lcov

Ubuntu系统

sudo apt install lcov

使用

对于lcov的使用方法可以通过下面这条命令查询:

lcov --help

通过输出我们可以看到,这个命令的参数有简短(例如-c)和完整(例如--capture)两种形式,其作用是一样的。

这里主要关注的下面这几个参数:

  • -c 或者 --capture 指定从编译产物中收集覆盖率信息。
  • -d DIR 或者 --directory DIR 指定编译产物的路径。
  • -e FILE PATTERN 或者 --extract FILE PATTERN 从指定的文件中根据PATTERN过滤结果。
  • -o FILENAME 或者 --output-file FILENAME 指定覆盖率输出的文件名称。

另外还有需要说明的是:

  • lcov默认不会打开分支覆盖率,因此我们还需要增加这个参数来打开分支覆盖率的计算:--rc lcov_branch_coverage=1
  • lcov输出的仍然是一个中间产物,我们还需要通过lcov软件包提供的另外一个命令genhtml来生成最终需要的html格式的覆盖率报告文件。同样的,为了打开分支覆盖率的计算,我们也要为这个命令增加--rc lcov_branch_coverage=1参数

最后,make_all.sh脚本中包含的相关内容如下:

COVERAGE_FILE=coverage.info
REPORT_FOLDER=coverage_report
lcov --rc lcov_branch_coverage=1 -c -d build -o ${COVERAGE_FILE}_tmp
lcov --rc lcov_branch_coverage=1  -e ${COVERAGE_FILE}_tmp "*src*" -o ${COVERAGE_FILE}
genhtml --rc genhtml_branch_coverage=1 ${COVERAGE_FILE} -o ${REPORT_FOLDER}

这段代码从我们前面编译的结果中收集覆盖率结果,并将结果输出到coverage.info_tmp文件中。但是这里面会包含非项目源码的覆盖率(例如google test),所以我们又通过另外一条命令来指定”src”文件夹进行过滤。最后,通过genhtml得到html格式的报告。

可以通过浏览器查看覆盖率报告的结果,像下面这样:

从这个报告的首页,我们已经可以看到代码的语句覆盖率(Lines),函数覆盖率(Functions)以及分支覆盖率(Branches)。而对于条件覆盖率可以从详细页面中看到。如下图所示:

在上面这张图中,我们可以看到哪些代码被覆盖了,哪些没有。而对于对于if-else之类的语句,也能很清楚的看到条件覆盖率的覆盖情况。例如,对于代码的27行,只覆盖了if成立时的情况,没有覆盖if不成立时的情况。

更进一步

本文中,我们已经完整的完成了从编写单元测试到覆盖率生成的整个过程。

但实际上,对于这项工作我们还可以做得更多一些。例如下面这两项工作:

使用Google Mock

Google Mock是Google Test的扩展,用于编写和使用C++ Mock类。

在面向对象的编程中,Mock对象是模拟对象,它们以预先设定的方式模仿真实对象的行为。程序员通常会创建一个Mock对象来测试某个其他对象的行为,这与汽车设计师使用碰撞测试假人来模拟人类在车辆碰撞中的动态行为的方式非常相似。

关于Google Mock的更多内容请参见:Google Mock的文档。

持续集成

对于演示项目的覆盖率报告是通过手动执行脚本文件生成的。

而在实际的项目中,可能同时有很多人在开发同一个项目,每一天项目中都会有很多次的代码提交。我们不可能每次手动的执行编译和生成覆盖率报告结果。这时就可以借助一些持续集成的工具,定时自动地完成项目的编译,测试和覆盖率报告结果的生成工作。

可以在持续集成工具中包含我们编写的脚本,然后将覆盖率报告的html结果发布到某个Web服务器上,最后再以邮件的形式将链接地址发送给大家。

这样就可以很方便的让整个团队看到所有模块的测试结果和覆盖率情况了。

完成了一整套这样的工作,可以非常好的提升整个项目的质量。

辑部 发自 凹非寺

量子位 报道 | 公众号 QbitAI

“一起花光比尔盖茨的8000万美金,来不来?”

23年前,李开复跟张亚勤这样“画饼”,于是亚洲最牛的计算机研究院就此诞生!

如今,他们一个是最具影响力的VC代表,他创办的创新工场已成为很多技术创新和前沿科技企业的精准捕手,他出版的书籍,不少登上畅销书排行榜。

另一个则是清华智能产业研究院院长、清华智能科学讲席教授,前不久他刚当选中国工程院外籍院士。加之此前美国艺术与科学院院士、澳洲国家工程院院士,成为“三院院士”

结果在MEET2022智能未来大会的现场,两人时隔多年首次同台,在近两百万观众面前,揭秘相识往事,也分享了各自对于科技发展趋势的看法。

从网友的反应上看,这次巅峰对话足以满足他们的期待。甚至还吸引了数十家主流媒体关注报道。

巅峰对话还有哪些亮点?以及十余位顶级AI大咖分享更多精彩内容,老样子,我们详细道来,一文看尽。

李开复张亚勤揭秘相识往事

李开复张亚勤的巅峰对话环节,主要讨论了三个方面。

首先,他们回忆起23年前回国创建微软亚洲研究院MSRA的事情。

当时李开复给张亚勤打电话,就“画了很大的饼”。他们想一同打造中国计算机的黄埔军校,以此证明给全世界看,中国人也能做最顶级的科研。

结果就在张亚勤决定回国,到北京第一天就被李开复修理了。

嗯,理发的理。

张亚勤回忆到,当时跟沈向洋一同回国,头发因为很长时间没打理,他们就被李开复带去理发了。

如今回过头看,当初说要建立个亚洲最牛、全球一流的计算机实验室这一个目标,在张亚勤看来已经实现,尤其在培养人才这方面。

而且过程中,也有让他们感到意外和大受震撼的进展。

比如李开复举例,谁能想到后来的AI四小龙的创始团队,都有微软亚洲研究院的背景。

还有像现在顶尖高校、大企业CTO以及一些创业公司,都有特别多当时培养的人才。

我们感觉特别欣慰,有种桃李满天下的感觉。

接着,他们探讨了当下最流行议题和技术风向。

比如元宇宙

李开复认为,它肯定会到来的,但五年之内不会有特别巨大的公司或应用出现。

张亚勤则补充,要用开放的心态去看待元宇宙。

一方面,如果说,元宇宙是真实世界与虚拟世界的融合,但以真实世界为主的话。

很多公司已经在做了,目前产品形态是技术的一种拓展。

另一方面,要说元宇宙是完全的虚拟世界,和真实世界没关系,那可能走得就太远了一点。现在也有不少炒作,技术也并不成熟,还需要不断地发展。

再比如,科学家创业的热议趋势。

两位老朋友一致认为,科学家创业需要一个企业家伙伴

张亚勤还补充道,科学家还需要专注。如果决定创业,那就出来做这件事。他认为科学家同时上课做科研,还要管理公司是很困难的。

最后他们放眼未来,有哪些领域和赛道值得看好。

张亚勤提及了AI与生物计算和生命科学交叉、无人驾驶和智慧交通,以及IOT。

而李开复Pick的第一个与张亚勤相同,除此之外还有机器人领域,尤其在工业制造上的应用,以及自然语言理解。

尤其是自然语言理解,李开复认为它在近几年的发展跟当年CNN、DNN一样,正从感知智能迅速迈向认知智能。未来AI一旦超越人类,就能做很多辅助、取代人类的工作。

而至于自身的未来小目标,张亚勤还是继续3.0人生——把AIR做起来,李开复则是想用行动证明做高科技的投资回报要比互联网更高。

哦对,这当中还有个小插曲。

当两位被问到,如果有项超能力——可以复制对方的能力,那会如何选择。

李开复首先就说,会复制张亚勤12岁就能读大学的天才能力。

而张亚勤,最想复制李开复吃遍美食还不胖”的能力。

此外,亚勤还说想复制他对未来的洞察,以及可以用简单的语言把复杂事物表述总结出来的能力。

李开复和张亚勤的巅峰对话,由量子位总编辑李根主持,在对话环节最后,他表示能够促成开复和亚勤的这样一次“老友对谈”,是量子位一直以来的愿望——

不仅是因为两位大咖今时今日的地位和成就,更是因为他们在23年前作出的回中国的决定,某种程度上来讲,奠定了如今智能未来的基础。

而且更关键的是,开复和亚勤,还都在继续为产业培育人才、鼓励创新,是中国智能产业领域当之无愧的两座高峰。

清华张亚勤:下个十年是AI与生物制药融合的大好时机

实际上,在巅峰对话开始前,清华大学智能科学讲席教授、清华智能产业研究院院长张亚勤,还以开场主题演讲的形式,分享了他对趋势——特别是AI+生命科学的判断。

清华智能产业研究院AIR于2020年成立,其使命是用人工智能技术赋能产业推动社会进步。

清华AIR选择了三个方向作为突破点:智能交通、智慧物联、智慧医疗。张亚勤这次分享的重点是智慧医疗方向中,人工智能如何赋能生命科学。

他认为整个信息产业过去三十年最大的突破就是数字化,从开始的内容数字化、企业数字化,到现在进入物理世界的数字化和生物世界的数字化。

一方面我们的身体从大脑、器官,到细胞、蛋白质、基因、分子都在数字化,另一方面人工智能算法、算力和系统的快速进展让大量数据有了使用的场所。

以前新药研发需要超过十几年的周期,十亿美元的投入, AI正在改变这种状况。

新冠疫苗去年年底进入临床试验,今年大规模使用,这可能是人类历史上最快的一次计算机科学包括人工智能加速疫苗开发的例子。

另外迁移学习用少量原始数据加上动物模型快速发现了对罕见病的药物,几何深度学习找出了广谱、稳定的新冠抗体,对变种株也有效,Swin Transformer用于测序基因里90%的未编码部分……

张亚勤总结道,AI和生命科学有很多可合作的地方,能让生物制药更快速、精准、安全,更经济、普惠。

但同时也有很多壁垒,算法的透明性、可解释性、隐私安全、伦理等挑战,以及如何把两个行业无缝连接起来。

由此研究院提出了「AI+生命科学破壁计划」作为前沿研究任务,跨越两个领域的鸿沟、打破壁垒促进AI与生命科学的深度交叉融合,构建AI+生命科学的研究和技术生态。

张亚勤看见了生物世界的数字化和AI技术的进展,相信下个十年是生物制药和人工智能融合的大好时机,也是行业发展的最大的机遇。

百度吴甜:技术创新持续为产业发展注入新动能

百度集团副总裁、深度学习技术及应用国家工程实验室副主任吴甜解读了技术创新与产业发展的关系。

根据中国信息通信研究院的数据,2020年我国数字经济已经达到了39.2万亿元,占GDP总值的38.6%,位居世界第二。未来这个数值的绝对值和相对比例都会持续增加,数字产业化和产业数字化齐头并进。

产业发展角度,可以看到产业使用人工智能的场景广泛且分散,技术与产业的结合越来越深入、专业,未来前景会更大更广阔。

技术发展角度,人工智能呈现出明显的融合创新趋势,包括软硬一体融合、跨模态多技术融合、知识与深度学习融合、技术与场景融合。

虽然底层技术越变越复杂,但所幸能够通过开源开放的人工智能平台降低门槛,使AI开发变得越来越容易。

如金融领域常见的智能合同解析与管理场景,传统都是靠人工方式从合同中提取三十多个维度信息,效率低,而保险的产品迭代速度又很快,相应的保险条款也在增加和变化,人工识别一份合同需要30分钟。技术工程师在开发平台上使用ERNIE训练了条款智能解析模型,并持续进行迭代优化,部署到保险业务平台中,提供智能解析能力,对合同文本实现了智能解析,达到通过智能辅助后单份合同解析时长缩短为1分钟。

像这样的变化,在各个行业当中都在发生。

吴甜总结道,一方面是产业的需求越来越旺盛,越来越多和广泛,另一方面技术本身也给我们带来新的想象空间,技术创新持续为产业当中运用人工智能技术注入新的动能,注入新的活力。

IBM谢东:如何让技术创新驱动环境智能和企业可持续发展

IBM副总裁、大中华区首席技术官谢东博士为我们分享「加速科技创新,共赢可持续未来」的议题。

从全球发展状况来看,可持续发展是我们共同面对的战略议题。世界经济论坛2021年全球风险报告指出,未来十年企业面临前的三大业务风险都与环境相关。

在中国双碳目标下,可持续发展不光是我们所有企业的社会责任,更加已经成为企业必须面对的战略议题。对于企业应该如何面对这些挑战,新技术突破会给行业带来哪些转变?

谢东博士从三个维度做了梳理。

企业治理角度,IBM非常注重可持续发展问题,早在50年前,制定了首个企业环境的政策,2000年提出二氧化碳减排目标;与全球各行业客户建立可持续发展咨询委员会。

当中还为助力中国企业实现碳中和制定四阶段战略建议,包括确保合规、优化流程及供应链、重塑业务、引领行业。

基于环境问题,IBM推出环境智能套件,涵盖人工智能、数据分析、环境数据分层、混合云、物联网与区块链。

在技术平台助力环境议题和创新的维度,以IBM位于苏黎世的云上自主化学实验室RoboRXN为例,全球可以通过网络直接访问到实验室,远程完成了从文献检索到一些科研探索,再到功能验证各个环节。

过去两年,化学实验室RoboRXN采用的免费AI模型,已经为学生、科学家和实验者完成了近100万次反应预测。

而背后能支撑这一系列环境和可持续发展创新的底层计算技术又是怎样的?谢东博士提到了最新推出的2nm芯片技术、带有片内AI加速器的处理器Telum,以及前不久发布的突破127 量子位量子处理器。谢东博士认为,量子计算机规模化商用可能已经在不远的未来了。

小冰李笛:AI相比人类创作者,不存在瓶颈期

小冰公司首席执行官李笛认为,有时候人们会过于高估人工智能在IQ方向的进展,却低估了人工智能在EQ方面蕴藏的巨大潜力。

那些出现在人类身边、与人类共存的「AI being」都应该有自己擅长和不擅长的领域,有自己的性格和观念,无所不知、无所不能的AI反而是面目不清的。

在迪拜世博会中国馆,正在展出AI画家夏语冰的一系列水墨画作品《山水精神》。

夏语冰除了创作能力也有着自己的面容、口音和创作观念,与另一位AI画家山东大哥完全不同。

李笛指出,如果要赋予AI创造力,它对不同事情的观念要有一致性,并反映在其所创造的东西上,才能让人类不感到违和。

当人工智能习得一定创作能力的时候,和人类创作者区别是什么?

第一,人类创作到了巅峰之后便开始滑坡,人工智能没有巅峰,要么是停滞的、要么会继续向上攀登,时间周期非常久。

第二,人类在同一时间只能专注地做一件事情,但人工智能是可以高并发的。

创造力只是小冰框架中的一小部分,最难的是如何赋予AI有趣的灵魂,真正和人类交流。

李笛看到人工智能在EQ方面蕴藏的巨大潜力,他相信我们这一代是与多样的人工智能生活在一起的第一代人类。

Rokid祝铭明:元宇宙更应专注虚实融合

Rokid创始人CEO祝铭明则在大会上探讨了AR智能眼镜行业的应用落地探索。

当前大家谈元宇宙,很多人谈的是创想与未来,Rokid关注的是技术落地能力,主要有5个方面:

感知——理解——协同——展现(光学技术、图形引擎)——数字资产/内容(创作、生产工具)

祝铭明介绍,Rokid是一家产品平台型公司,除了上述五种能力,还会考虑一些载体去做和大家进行交互,也根据自己思考分成了四个象限。

横轴代表以穿戴性、佩戴性为出发点去衡量,从专用场景到日常佩戴(从左到右)。

纵轴是以展现能力为一个衡量点去思考,从内容属性到工作属性(从上到下)。

第一层,感知能力,如半导体、传感器等技术。

第二层,关注在感知基础上如何理解世界,理解周边的环境、理解人、理解事。

第三层为协同,深度思考人和人、人和事物之间的协同关系,但不是创造虚拟世界,而是融合真实世界和数字世界。

第四层,视觉和感官层的展现能力,背后涉及光学、图形引擎、算法、空间引擎等技术。

最后,为数字资产(数字内容生产)。包括创作工具、生产工具、管理、安全等方面的能力。

过程中,祝铭明还强调,Rokid做人机交互有着不同的阶段,从最早指令型的人机交互,到后面图形化的所见即所得的人机交互,对人类越来越友好。

在分享的最后,他提出了自己对于元宇宙的思考。

如果元宇宙是一种发展方向,那我们觉得元宇宙不应该是局限于虚拟世界,如何将人与真实世界和虚拟世界做一个完整的融合,不应该割裂开,这是我们一直在主导的事情。

他看到了人机交互的巨大潜力,他相信在未来,真实世界跟数字世界将进行融合而非割裂。

亚信科技欧阳晔:5G把AI 能力投送到边缘


亚信科技首席技术官、高级副总裁欧阳晔带来了《5G网络助推边缘AI》的主题演讲。

以2006年AI第三次发展浪潮开始作为节点到现在的15年间,通信领域与AI相关的学术成果发表数量是之前15年的6.42倍。同时随着5G技术与业务的发展,云端智能需向边缘迁移。

通信技术作为数字化转型的基础设施,该如何利用5G通信技术把AI能力投送到千行百业的边缘触点?

欧阳晔博士介绍了5G网络投送AI能力到达边缘的三种模式:

  • 5G网络切片,可以理解成在现有的公有网络里构建一层专用的高速隧道。
  • 5G独立专网,企业搭建的私有网络。
  • 5G混合专网,专网与公网共享基站的模式。

AI能力投送到边缘后并不是就能直接应用到各种to B和to C场景,而是通过第五代移动通信边缘计算平台承载多种通用目的技术(如AI,数字孪生,数据治理与AIoT等)构建云边端协同整体方案。

随后欧阳晔介绍了基于五代移动通信边缘计算平台的智慧电厂、智慧工地和智慧园区3个典型场景案例。

欧阳晔指出通信和AI两个领域的发展相关性将越来越强,他相信在未来,应用层厂家、通信基础设施厂家以及运营商合作伙伴要共同努力,共同触及通信人工智能未来十年的发展。

京东何晓冬:对话本质上是博弈与决策,语言只是一种表现形式

京东集团副总裁、京东探索研究院常务副院长何晓冬则分享了多模态智能人机交互技术在复杂场景中的进化,以及技术落地给人类创造价值。

提到人工智能,往往会想到语音识别,图像识别、人脸识别、甚至机器翻译。

对话智能是种什么智能?某种程度上讲是一种融合性智能,前面提到单点基础技术都被融合在其中。

简单说,对话智能就是希望打造一个机器,它能够自如像人一样跟你对话交流沟通关怀,完成任务。

表现上看,它是种非常自然地交互方式;从技术上看,它需要感知智能、情感智能、认知智能、多轮对话管理。

何晓冬认为,对话即决策,本质上来说对话本质上是博弈与决策,语言只是一种表现形式。

接着,何晓冬介绍了在京东是如何迭代技术、让这项技术为更多用户所用、创造更多的价值。

简单来说,两种模式并行:打造前沿的技术能力,同时把前沿的技术推向千行百业应用落地。

刚刚过去的双十一,何晓冬团队通过智能人机对话系统打造的京东智能客服言犀,累计服务了超过7.4亿咨询量、16.5万的第三方商家,智能物流预约外呼超过了193万通电话,完成2.1亿次的质量检测,在整个京东的售前、售中、售后、物流各个环节实现了客服服务全链路的场景智能化。

大会现场何博士还给我们演示了智能人机对话系统服务成都顾客的真实案例~

而为了让机器人做得更好,京东还打造了五个维度的服务评价质量指数,来评价机器人和人之间的差距,展示京东在智能人机对话领域深刻的沉淀。

除了服务京东本身以外,他们的多模态智能人机交互技术还运用到更多行业当中去,比如政府的政务热线、金融行业的业务客服等。

展望未来五年,人工智能的三大支柱数据、算力、算法,都会得到进一步升级场景、系统、算力。

数据升级成持续运作的“活”场景数据;单点的算法进一步提升至综合性的AI系统,包括多算法互相协同、联合优化,这样才能打造真正端到端、高价值的AI系统。

商汤杨帆:AI算法下一个时代是端到端系统化整合

商汤科技联合创始人、商汤集团副总裁杨帆认为,赋能产业升级是AI的核心价值所在。

今天在各行各业都有对AI的刚需存在。

如工业检测分析的痛点是效率低、漏检率高和标准不统一、检测人员水平差异大等。城市管理分析中事故的偶发性高、分散,需要大量人力投入。

杨帆说,眼下AI企业会越来越面临一种「幸福的烦恼」。

幸福之处在于刚需大量存在,烦恼之处在于刚需碎片化、场景多样化,AI企业提供技术创新的成本,包括边际成本比较高,造成了AI产业进一步发展面临的供需匹配失调的问题。

要解决这些烦恼一方面需要有通用能力的基础设施为人工智能产业创新提供支撑,另一方面需要跨组织之间的联合和协作。

杨帆从在商汤做算法的经历出发,总结出算法的三个时代。

第一个时代像手工业,非常依赖个体科学家的个人水平。

第二个时代就是过去这5年,像工业化流水线,能够用更多系统把算法创造的各个环节整合打通,持续的规模化的生产技术创新。

下一个时代该是什么?杨帆认为技术创新会走向更加通用、低成本高效,就像工业流水线趋势是自动化智能化。

从底层基础设施,到硬件,再到软件和上游应用,形成端到端系统化模式,把各个环节进行更加标准化的定义以及有机组合。

端到端整合可以带来更高的安全性以及更低的网络时延,同时把算法打造成像乐高积木块一样,提供给产业内的大家共同去打造有价值的应用。

杨帆看到了行业刚需当下没有被很好的满足,他相信平台化、规模化、低成本高效率的工具体系,会让整个产业技术创新走得更快。

思谋刘枢:AI技术正在成为一种新型生产要素

思谋科技联合创始人兼技术负责人刘枢在大会分享了思谋科技如何用AI推动制造业数字化智能化转型。

人工智能在推动经济发展的同时,也在创造虚拟劳动力,去做人类不想做、做不好、不能做的事情,同时当人工智能在很多行业落地的时候,可以拉动其上下游协同发展和创新。

因此作为两年即长成独角兽的思谋科技,认为“人工智能技术正在成为一种新的生产要素”。

埃森哲曾预测到2035年,人工智能可以将年经济增长率额外提升1.6%,人工智能作为单独技术将额外带来8千亿美金增长,而如果作为生产要素去评估,将带来6万亿美金的规模增长。

再来看制造业的发展,总共经历了三个阶段:自动化-信息化-智能化,如今智能制造蕴含着巨大发展机遇。

智能制造,关键在于智能——即让制造拥有大脑,自动化只是手臂,把决策变为现实。但实际落地过程中,思谋科技遇到了些有意思的问题,这与熟悉的自然场景有许多不同。

首先,数据极度短缺。在工业场景里面,很多时候每一种缺陷的图片数量都达不到10。

第二,工业验收要求非常高。以手机为例,如果要求手机成品良率99%,假设一台手机含200个零件,那么每个零件良率都需达到99.99%。

第三,被检形态非常多。常用器件就可能有成百上千种不同的形状。

第四,缺陷难以区分。

刘枢认为,只有当系统可以自动实现算法组合和部署,人类只需要少量定制化算法设置的时候,才有可能实现AI跨领域规模产业化。

如果没有自动实现算法组合和部署的系统,在高端制造业实现AI全面产业化会非常艰难。

以智能手机为例,零件供应商平均来讲有400个,每个供应商有五个制程,每个制程又有15条产线,如果一条产线都做一个模型,大概要做3万个模型。

再放眼全行业前五的品牌,每个品牌6款产品,则需要90万个不同的算法模型,这其中还不算第二年、第三年的软硬件升级迭代。

为了达到这一目标,思谋科技研发了AI算法平台SMAP,以及沉淀了AI Know-How的DataFlow系统。

最后,刘枢还分享了智能制造的核心原则:普适性,计算为先和永不间断的学习。

当AI系统设计能够自动化,当AI部署和运营能够自动化的时候,就一定能够实现新一代智能产业的变革。

数牍科技蔡超超:隐私计算,构建下一代数据流通底层的关键设施

数牍科技联合创始人兼CTO蔡超超分享的主题是《隐私计算构建下一代数据流通底层的关键设施》。

刚才我们提到智能驾驶场景,就和隐私计算有很大的相关性。

智能汽车在运行过程中产生大量图片、音频甚至位置数据,都涉及到用户的隐私。这些数据的高效开发利用需要在保护数据安全的情况下进行,需要用到隐私计算。

隐私计算是一种在数据不可见的前提下,让信息进行价值流通的工程和技术体系,涉及多方安全计算,联邦学习、可信执行环境、差分隐私、同态加密、区块链等多种技术。

蔡超超同时认为隐私计算体系不是一个单一的系统,它其实是一个网络,一个底层平台,包含了不同的参与方。

每个参与方的主体可能是人、是车或其他设备,这些主体都会有自己的ID,比如身份证、电话号码、设备号,在数据合作之前需要有共同的语言把ID有效统一对齐起来,才能进行安全的数据协作。

基于隐私计算的ID系统可以做到匿名化、原始ID和敏感信息不可追溯、不可还原。

接下来,让多方在不交换原始数据的前提下进行安全合规的数据协作,应用于反欺诈、反洗钱、精准营销、联合风控等一系列场景。

蔡超超看到了有数据价值交换的地方就有隐私计算的需求,他相信隐私计算平台发展过程中需要注重安全可靠性、有完整的数据科学应用体系以及工业级落地能力。

智驾周圣砚:以规模化迎接智能驾驶平权时代

智驾科技创始人兼CEO周圣砚在大会上分享了智驾视角下自动驾驶产业以及今后发展是如何的。

一开场,周圣砚就举了一个小例子:如果问消费者,什么品牌汽车做的比较好,消费者能轻易列出答案。但如果问自动驾驶有哪些比较好的公司,可能大多数消费者都没办法答出。

为什么会有这样的现象?如果回顾互联网行业的发展,就会发现它之所以能蓬勃发展,是因为覆盖了最广大用户群体。

回顾过去几年自动驾驶的发展一直非常曲折,原因在于大家一直在技术路径和商业模式上产生强烈的争议。如今这些争议依旧存在,但同时也确实感受到自动驾驶正在实现并产生社会的正向价值

SAE把自动驾驶从工程学的角度分了L0-L5不同驾驶等级,智驾科技MAXIEYE今天从解决问题的角度重新分解自动驾驶等级。

首先,即第一个等级,需要解决的是安全问题,比如车辆的紧急制动系统。

第二个等级,驾驶过程中的舒适性问题,比如高速公路实现的全速巡航系统。

第三个等级,解决出行效率问题。智驾科技MAXIEYE认为在结构化道路,比如城市道路和高速公路,可以实现点到点的自动驾驶功能。

第四个等级,优化交通能源的问题,比如干线无人物流。前三个等级叫做人机共驾,最后一个等级才叫做无人驾驶。

最后,他希望与行业一起迎接智能驾驶科技平权时代的到来。

从市场维度,产品全面下探最广泛的5-15万元车型,将覆盖最广大的用户群体;从消费者维度,提供消费者用得起愿意用的智能驾驶产品;从产业链维度,全行业开放共创,建立行业共识和技术协同,全产业链去共同打造智能驾驶科技平权时代。

周圣砚看到自动驾驶需要覆盖更广大用户群体,他相信未来AI将以数据驱动方式助力智能驾驶系统越用越聪明。

自动驾驶圆桌论坛:量产、安全,变局时刻

大会的最后阶段,自动驾驶行业大佬们围绕「量产」展开了激烈讨论。

先来介绍一下各位嘉宾:

腾讯交通平台部总经理、自动驾驶总经理苏奎峰

过去一年腾讯从自动驾驶测试工具链,以及智能联网示范区、智慧高速等车路协同解决方案两个方面助力产业发展。

无人驾驶公司驭势科技联合创始人、首席系统架构师彭进展

驭势科技开展了无人车在多个场景的商业化运营,拥有在机场、工厂等场景几百台车7x24小时、365天持续不断的运营能力。

无人卡车公司主线科技CEO张天雷

主线科技专注于自动驾驶卡车,在几个港口物流枢纽还有京津高速、京沪高速上运行的车辆规模有150辆车左右,每天都在持续地运行。

那么开始第一个话题,2021年怎么就成了自动驾驶量产集中的一年?

首先三位嘉宾都认为政策很关键,三个团队创业之初都获得了资金支持,来自国家自然科学基金。

另外今年从北上广深到武汉、长沙、无锡再到衡阳,无论一线还是二三线城市都开始积极推动无人驾驶落地。

张天雷提出第二个因素:场景

张天雷觉得物流场景尤其是封闭的完全无人的,还有高速以及一些城区限定区域内的场景,从今年开始包括到明年年底很有可能有很多批量的应用出来。

彭进展的角度是技术进展,无人驾驶如果不能把安全员拿掉,就体现不出真正的价值。

只有真正把安全员拿掉,你的客户和合作伙伴才会相信这件事真的能成功。

最后苏奎峰总结发言,政策、场景和技术全都交汇在今年这一点,无人驾驶量产终于到来。

第二个话题:量产之后,大众都「看见」了自动驾驶,未来行业会面临哪些新的挑战?

虽然问题比较宽泛,不过三位的表达不约而同的集中在了安全这个点。

苏奎峰提到,只要自动驾驶的量产规模大了,原本的一些小概率事件也会变成常发事件,这不代表技术不好,但确实有许多长尾的问题需要预见和克服。

他强调:

我们在安全性、稳定性上要有敬畏心。

彭进展认为无人驾驶在安全上的优势在于实时性,实时监控反映,实时通过AI去控制。

虽然理论上可以计算出无人驾驶事故概率就是远远低于人类驾驶,但实际中还需要做进一步验证。

每天都会发生人为因素引起的交通事故,但对于大众来说并不算什么新闻。期待有一天,大众对自动驾驶出事故也有一个平常的心态。

张天雷则指出没有一个系统能够百分之百的保证总是正常运行,我们要做的是把出错的代价降到最小,核心的问题是不要有人员的伤亡。

在任何时候,自动驾驶的安全性永远排在第一位。为了系统的安全性,付出再多代价也是需要的。

圆桌讨论的最后一部分,是每人分享一件行业中最感到意外的事。

苏奎峰:

到头来是新能源加速了自动驾驶落地。

彭进展:

震撼最大的是行业真的做到把安全员拿掉了。

张天雷:

特斯拉投入巨大精力做数据驱动,造了世界上排行第五的超算机群来训练模型,这是中小型国家都做不到的。

从那时开始,大家明白了一个道理,自动驾驶是个军备竞赛。

因为看见,所以相信

过去的一年,是复杂变化的一年。

但前沿科技始终是社会发展的重要动力,也蕴藏着无比的机遇。AI大模型、自动驾驶、生物计算等领域正在加速改变世界,前沿计算、新型储能等方向新探索不断涌现。

与此同时,前沿技术的落地也愈发如火如荼。新技术、新产品让我们的生活越来越好,越来越有趣。

不过一切也并非一帆风顺。

量子位创始人兼CEO孟鸿表示,前沿科技的发展总是起起伏伏,发展的范式会改变,上升的道路会改变,但前进的趋势不会改变。

今年到场的来宾,都是因为对前沿科技有一份坚定的相信,进而选择在这个方向上不断推动世界前进。

整场大会下来可以看到,他们今年交出的商业化落地答卷,在更深入现实的地方被交出。

而这也只是今年诸多技术创新案例中的一隅。

作为人工智能年度最佳落地参考,「2021人工智能年度评选」结果也已揭晓。在过去2个月时间里,共有数百家科技企业、机构和个人报名参与评选。

最终评选出50大领航企业、20大最具价值创业公司、30大创业领袖、20大技术领袖、10大最佳产品以及10大最佳解决方案等在内人工智能领域年度奖项。

这些无一不在印证本次MEET智能未来大会主题:因为看见,所以相信。

希望让更多人看到前沿科技的进展和落地,让更多人进一步相信前沿科技背后蕴藏的巨大价值。

那么这一年,你看见了什么?从而又相信着什么?

Ps,也许量子位最新发布的「2021人工智能年度评选」,可以给你参考,链接在此:https://mp.weixin.qq.com/s/E3wcXr3PA0uZAZ1N-lgThg。

Pps,如果想回顾精彩内容,回放链接在此!
微吼:http://live.vhall.com/127740714
微博:https://weibo.com/l/wblive/p/show/1022:2321324707747747987514
百家号:https://live.baidu.com/m/media/multipage/liveshow/index.html?room_id=5008651533
CSDN:https://live.csdn.net/room/wl5875/tVtNmdeX
斗鱼:https://v.douyu.com/show/85BAvqrrERB7G4Lm?ap=1

— 完 —

量子位 QbitAI · 头条号签约

关注我们,第一时间获知前沿科技动态