2020年2月27日 星期四

[Openvino] Install Intel® Distribution of OpenVINO™ toolkit for Linux* Using APT Repository

http://docs.openvinotoolkit.org/latest/_docs_install_guides_installing_openvino_apt.html

By downloading Intel® OpenVINO you agree to the terms and conditions stated in the Intel Simplified Software License.

NOTE: Intel® Graphics Compute Runtime for OpenCL™ is not a part of OpenVINO™ APT distribution. You can install it from the Intel® Graphics Compute Runtime for OpenCL™ GitHub repo.

Set up the Repository

Install the GPG key for the repository

  1. Download the public key from https://apt.repos.intel.com/openvino/2020/GPG-PUB-KEY-INTEL-OPENVINO-2020 and save it to a file.
  2. Add this key to the system keyring:
    sudo apt-key add <PATH_TO_DOWNLOADED_GPG_KEY>
  3. Check the list of APT keys running the following command:
    sudo apt-key list

Add the APT Repository

  1. Navigate to the repositories directory:
    cd /etc/apt/sources.list.d
  2. Create a new source list file:
    sudo vi intel-openvino-2020.list
  3. Add the following code:
    deb https://apt.repos.intel.com/openvino/2020 all main
  4. Save and close the file intel-openvino-2020.list.

Update the list of packages

Run the update command:
sudo apt update
There are full release Runtime and Developer packages, and also some available components.
Runtime Packages
  • Ubuntu 18.04: intel-openvino-runtime-ubuntu18
  • Ubuntu 16.04: intel-openvino-runtime-ubuntu16
Developer Packages
  • Ubuntu 18.04: intel-openvino-dev-ubuntu18
  • Ubuntu 16.04: intel-openvino-dev-ubuntu16

Get the list of available packages

Run the apt-cache command to see a list of all available OpenVINO packages and components:
apt-cache search openvino

Examples

  • Runtime Packages
    On Ubuntu 18.04:
    sudo apt-cache search intel-openvino-runtime-ubuntu18
    On Ubuntu 16.04:
    sudo apt-cache search intel-openvino-runtime-ubuntu16
  • Developer Packages
    On Ubuntu 18.04:
    sudo apt-cache search intel-openvino-dev-ubuntu18
    On Ubuntu 16.04:
    sudo apt-cache search intel-openvino-dev-ubuntu16

Install the runtime or developer packages using the APT Package Manager

Intel® OpenVINO will be installed in: /opt/intel/openvino_<VERSION>.<UPDATE>.<BUILD_NUM>
A symlink will be created: /opt/intel/openvino

To Install a specific version

To get a list of OpenVINO packages available for installation:
sudo apt-get search intel-openvino-runtime-ubuntu18
To install a specific version of an OpenVINO package:
sudo apt install intel-openvino-<PACKAGE_TYPE>-ubuntu<OS_VERSION>-<VERSION>.<UPDATE>.<BUILD_NUM>

Examples

  • Runtime Package
    On Ubuntu 18.04:
    sudo apt install intel-openvino-runtime-ubuntu18-2020.1.023
    On Ubuntu 16.04:
    sudo apt install intel-openvino-runtime-ubuntu16-2020.1.023
  • Developer Package
    On Ubuntu 18.04:
    sudo apt install intel-openvino-dev-ubuntu16-2020.1.023
    On Ubuntu 16.04:
    sudo apt install intel-openvino-dev-ubuntu18-2020.1.023

    To Uninstall a specific version

To uninstall a specific full runtime package:
sudo apt autoremove intel-openvino-<PACKAGE_TYPE>-ubuntu<OS_VERSION>-<VERSION>.<UPDATE>.<BUILD_NUM>
Additional Resources

2020年2月19日 星期三

[轉載] linux中Oops信息的调试及栈回溯—Linux人都知道,这是好东西!

https://blog.csdn.net/kangear/article/details/8217329

https://blog.huzhifeng.com/2015/03/05/Linux-Kernel-Oops-%E8%B0%83%E8%AF%95/

=============================================================================
看后感想:這点比 ldd3上讲的都仔细
2012年11月29日11:24:17:有BUG_ON就不用反汇编了。。。
2012年11月30日11:14:13:回调函数跟丢了
=============================================================================
Oops 信息来源及格式
Oops 这个单词含义为“惊讶”
,当内核出错时(比如访问非法地址)打印出来的信息被
称为 Oops 信息。
Oops 信息包含以下几部分内容。
1 一段文本描述信息。
比如类似“Unable to handle kernel NULL pointer dereference at virtual address 00000000”
的信息,它说明了发生的是哪类错误。
2 Oops 信息的序号。
比如是第 1 次、第 2 次等。这些信息与下面类似,中括号内的数据表示序号。
Internal error: Oops: 805 [#1]
3 内核中加载的模块名称,也可能没有,以下面字样开头。
Modules linked in:
4 发生错误的 CPU 的序号,对于单处理器的系统,序号为 0,比如:
CPU: 0
Not tainted (2.6.22.6 #36)
5 发生错误时 CPU 的各个寄存器值。
6 当前进程的名字及进程 ID,比如:
Process swapper (pid: 1, stack limit = 0xc0480258)
这并不是说发生错误的是这个进程,而是表示发生错误时,当前进程是它。错误可能发
生在内核代码、驱动程序,也可能就是这个进程的错误。
7 栈信息。
8 栈回溯信息,可以从中看出函数调用关系,形式如下:
Backtrace:
[<c001a6f4>] (s3c2410fb_probe+0x0/0x560) from [<c01bf4e8>] (platform_drv_
probe+0x20/0x24)
...
9 出错指令附近的指令的机器码,比如(出错指令在小括号里)
:
Code: e24cb004 e24dd010 e59f34e0 e3a07000 (e5873000)
配置内核使 Oops 信息的栈回溯信息更直观
Linux 2.6.22 自身具备的调试功能,可以使得打印出的 Oops 信息更直观。通过 Oops 信
息中 PC 寄存器的值可以知道出错指令的地址,通过栈回溯信息可以知道出错时的函数调用
关系,根据这两点可以很快定位错误。
要让内核出错时能够打印栈回溯信息,编译内核时要增加“-fno-omit-frame-pointer”选
项,这可以通过配置 CONFIG_FRAME_POINTER 来实现。查看内核目录下的配置文件.config,
确保 CONFIG_FRAME_POINTER 已经被定义,如果没有,执行“make menuconfig”命令重
新配置内核。CONFIG_FRAME_POINTER 有可能被其他配置项自动选上。
18.3.3
使用 Oops 信息调试内核的实例
1.获得 Oops 信息
本小节故意修改 LCD 驱动程序 drivers/video/s3c2410fb.c,加入错误代码:在 s3c2410fb_
probe 函数的开头增加下面两条代码:
int *ptest = NULL;
*ptest = 0x1234;
重新编译内核,启动后会出错并打印出如下 Oops 信息:
Unable to handle kernel NULL pointer dereference at virtual address 00000000
pgd = c0004000
[00000000] *pgd=00000000
Internal error: Oops: 805 [#1]
Modules linked in:
CPU: 0
Not tainted (2.6.22.6 #36)
PC is at s3c2410fb_probe+0x18/0x560
LR is at platform_drv_probe+0x20/0x24
pc : [<c001a70c>]
lr : [<c01bf4e8>]
psr: a0000013
sp : c0481e64 ip : c0481ea0 fp : c0481e9c
r10: 00000000 r9 : c0024864 r8 : c03c420c
r7 : 00000000 r6 : c0389a3c r5 : 00000000 r4 : c036256c
r3 : 00001234 r2 : 00000001 r1 : c04c0fc4 r0 : c0362564
Flags: NzCv IRQs on FIQs on Mode SVC_32 Segment kernel
Control: c000717f Table: 30004000 DAC: 00000017
Process swapper (pid: 1, stack limit = 0xc0480258)
Stack: (0xc0481e64 to 0xc0482000)
1e60:c02b1f70 00000020 c03625d4 c036256c c036256c 00000000 c0389a3c
1e80: c0389a3c c03c420c c0024864 00000000 c0481eac c0481ea0 c01bf4e8 c001a704
1ea0: c0481ed0 c0481eb0 c01bd5a8 c01bf4d8 c0362644 c036256c c01bd708 c0389a3c
1ec0: 00000000 c0481ee8 c0481ed4 c01bd788 c01bd4d0 00000000 c0481eec c0481f14
1ee0: c0481eec c01bc5a8 c01bd718 c038dac8 c038dac8 c03625b4 00000000 c0389a3c
1f00: c0389a44 c038d9dc c0481f24 c0481f18 c01bd808 c01bc568 c0481f4c c0481f28
1f20: c01bcd78 c01bd7f8 c0389a3c 00000000 00000000 c0480000 c0023ac8 00000000
1f40: c0481f60 c0481f50 c01bdc84 c01bcd0c 00000000 c0481f70 c0481f64 c01bf5fc
1f60: c01bdc14 c0481f80 c0481f74 c019479c c01bf5a0 c0481ff4 c0481f84 c0008c14
1f80: c0194798 e3c338ff e0222423 00000000 00000001 e2844004 00000000 00000000
1fa0: 00000000 c0481fb0 c002bf24 c0041328 00000000 00000000 c0008b40 c00476ec
1fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
1fe0: 00000000 00000000 00000000 c0481ff8 c00476ec c0008b50 c03cdf50 c0344178
Backtrace:
[<c001a6f4>] (s3c2410fb_probe+0x0/0x560) from [<c01bf4e8>] (platform_drv_
probe+0x20/0x24)
[<c01bf4c8>] (platform_drv_probe+0x0/0x24) from [<c01bd5a8>] (driver_probe_
device+0xe8/0x18c)
[<c01bd4c0>] (driver_probe_device+0x0/0x18c) from [<c01bd788>] (__driver_
attach+0x80/0xe0)
r8:00000000 r7:c0389a3c r6:c01bd708 r5:c036256c r4:c0362644
[<c01bd708>] (_ _driver_attach+0x0/0xe0) from [<c01bc5a8>] (bus_for_each_
dev+0x50/0x84)
r5:c0481eec r4:00000000
[<c01bc558>] (bus_for_each_dev+0x0/0x84) from [<c01bd808>] (driver_attach+
0x20/0x28)
r7:c038d9dc r6:c0389a44 r5:c0389a3c r4:00000000
[<c01bd7e8>] (driver_attach+0x0/0x28) from [<c01bcd78>] (bus_add_driver+
0x7c/0x1b4)
[<c01bccfc>] (bus_add_driver+0x0/0x1b4) from [<c01bdc84>] (driver_register+
0x80/0x88)
[<c01bdc04>] (driver_register+0x0/0x88) from [<c01bf5fc>] (platform_driver_
register+0x6c/0x88)
r4:00000000
[<c01bf590>] (platform_driver_register+0x0/0x88) from [<c019479c>] (s3c2410fb_
init+0x14/0x1c)
[<c0194788>] (s3c2410fb_init+0x0/0x1c) from [<c0008c14>] (kernel_init+0xd4/
0x28c)
[<c0008b40>] (kernel_init+0x0/0x28c) from [<c00476ec>] (do_exit+0x0/0x760)
Code: e24cb004 e24dd010 e59f34e0 e3a07000 (e5873000)
Kernel panic - not syncing: Attempted to kill init!
分析 Oops 信息
(1)明确出错原因。
由出错信息“Unable to handle kernel NULL pointer dereference at virtual address 00000000”
可知内核是因为非法地址访问出错,使用了空指针。
(2)根据栈回溯信息找出函数调用关系。
内核崩溃时,可以从 pc 寄存器得知崩溃发生时的函数、出错指令。但是很多情况下,错
误有可能是它的调用者引入的,所以找出函数的调用关系也很重要。
部分栈回溯信息如下:
[<c001a6f4>] (s3c2410fb_probe+0x0/0x560) from [<c01bf4e8>] (platform_drv_
probe+0x20/0x24)
这行信息分为两部分,
表示后面的 platform_drv_probe 函数调用了前面的 s3c2410fb_probe
函数。
前半部含义为:
“c001a6f4”是 s3c2410fb_probe 函数首地址偏移 0 的地址,这个函数大
小为 0x560。
后半部含义为:
“c01bf4e8”是 platform_drv_probe 函数首地址偏移 0x20 的地址,这个函
数大小为 0x24。
另外,后半部的“[<c01bf4e8>]”表示 s3c2410fb_probe 执行后的返回地址。
对于类似下面的栈回溯信息,其中是 r8~r4 表示 driver_probe_device 函数刚被调用时这
些寄存器的值。
[<c01bd4c0>] (driver_probe_device+0x0/0x18c) from [<c01bd788>] (__driver_
attach+0x80/0xe0)
r8:00000000 r7:c0389a3c r6:c01bd708 r5:c036256c r4:c0362644
从上面的栈回溯信息可以知道内核出错时的函数调用关系如下,
最后在 s3c2410fb_probe
函数内部崩溃。
do_exit ->
kernel_init ->
s3c2410fb_init ->
platform_driver_register ->
driver_register ->
bus_add_driver ->
driver_attach ->
bus_for_each_dev ->
__driver_attach ->
driver_probe_device ->
platform_drv_probe ->
s3c2410fb_probe
(3)根据 pc 寄存器的值确定出错位置。
上述 Oops 信息中出错时的寄存器值如下:
PC is at s3c2410fb_probe+0x18/0x560
LR is at platform_drv_probe+0x20/0x24
pc : [<c001a70c>]
lr : [<c01bf4e8>]
psr: a0000013
...
“PC is at s3c2410fb_probe+0x18/0x560”表示出错指令为 s3c2410fb_probe 函数中偏移为
0x18 的指令。
“pc : [<c001a70c>]”表示出错指令的地址为 c001a70c(十六进制)。
(4)结合内核源代码和反汇编代码定位问题。
先生成内核的反汇编代码 vmlinux.dis,执行以下命令:
$ cd /work/system/linux-2.6.22.6
$ arm-linux-objdump -D vmlinux > vmlinux.dis
出错地址 c001a70c 附近的部分汇编代码如下:
c001a6f4 <s3c2410fb_probe>:
c001a6f4: e1a0c00d mov ip, sp
c001a6f8: e92ddff0 stmdb
c001a6fc: e24cb004 sub fp, ip, #4 ; 0x4
c001a700: e24dd010 sub sp, sp, #16 ; 0x10
c001a704: e59f34e0 ldr r3, [pc, #1248] ; c001abec <.init+0x1284c>
c001a708: e3a07000 mov r7, #0
c001a70c: e5873000 str r3, [r7]
c001a710: e59030fc ldr r3, [r0, #252]
sp!, {r4, r5, r6, r7, r8, r9, sl, fp, ip, lr, pc}
; 0x0
<===========出错指令
出错指令为“str r3, [r7]”
,它把 r3 寄存器的值放到内存中,内存地址为 r7 寄存器的值。
根据 Oops 信息中的寄存器值可知:r3 为 0x00001234,r7 为 0。0 地址不可访问,所以出错。
s3c2410fb_probe 函数的部分 C 代码如下:
static int __init s3c2410fb_probe(struct platform_device *pdev)
{
struct s3c2410fb_info *info;
struct fb_info
*fbinfo;
struct s3c2410fb_hw *mregs;
int ret;
int irq;
int i;
u32 lcdcon1;
int *ptest = NULL;
*ptest = 0x1234;
mach_info = pdev->dev.platform_data;
结合反汇编代码,很容易知道是“*ptest = 0x1234;”导致错误,其中的 ptest 为空。
对于大多数情况,从反汇编代码定位到 C 代码并不会如此容易,这需要较强的阅读汇编
程序的能力。通过栈回溯信息知道函数的调用关系,这已经可以帮助定位很多问题了。
使用 Oops 的栈信息手工进行栈回溯
前面说过,从 Oops 信息的 pc 寄存器值可知得知崩溃发生时的函数、出错指令。但是错
误有可能是它的调用者引入的,所以还要找出函数的调用关系。
由于内核配置了 CONFIG_FRAME_POINTER,当出现 Oops 信息时,会打印栈回溯信息。如
果内核没有配置 CONFIG_FRAME_POINTER,这时可以自己分析栈信息,找到函数的调用关系。
1.栈的作用
一个程序包含代码段、数据段、BSS 段、堆、栈;其中数据段用来中存储初始值不为 0
的全局数据,BSS 段用来存储初始值为 0 的全局数据,堆用于动态内存分配,栈用于实现函
数调用、存储局部变量。
被调用函数在执行之前,它会将一些寄存器的值保存在栈中,其中包括返回地址寄存器
lr。如果知道了所保存的 lr 寄存的值,那么就可以知道它的调用者是谁。在栈信息中,一个
函数一个函数地往上找出所有保存的 lr 值,
就可以知道各个调用函数,
这就是栈回溯的原理。
2.栈回溯实例分析
仍以前面的 LCD 驱动程序为例,
使用上面的 Oops 信息的栈信息进行分析,
栈信息如下:
Stack: (0xc0481e64 to 0xc0482000)
1e60:c02b1f70 00000020 c03625d4 c036256c c036256c 00000000 c0389a3c
1e80: c0389a3c c03c420c c0024864 00000000 c0481eac c0481ea0 c01bf4e8 c001a704
1ea0: c0481ed0 c0481eb0 c01bd5a8 c01bf4d8 c0362644 c036256c c01bd708 c0389a3c
1ec0: 00000000 c0481ee8 c0481ed4 c01bd788 c01bd4d0 00000000 c0481eec c0481f14
1ee0: c0481eec c01bc5a8 c01bd718 c038dac8 c038dac8 c03625b4 00000000 c0389a3c
...
1 根据 pc 寄存器值找到第一个函数,确定它的栈大小,确定调用函数。
从 Oops 信息可知 pc 值为 c001a70c,
使用它在内核反汇编程序 vmlinux.dis 中可以知道它
位于 s3c2410fb_probe 函数内。
根据这个函数开始部分的汇编代码可以知道栈的大小、lr 返回值在栈中保存的位置,代
码如下:
c001a6f4 <s3c2410fb_probe>:
c001a6f4:
e1a0c00d
mov ip, sp
c001a6f8: e92ddff0 stmdb
c001a6fc: e24cb004 sub fp, ip, #4 ; 0x4
sp!, {r4, r5, r6, r7, r8, r9, sl, fp, ip, lr, pc}
c001a700: e24dd010 sub sp, sp, #16 ; 0x10
e5873000 str r3, [r7]
...
c001a70c:
// pc 值 c001a70c 对应的指令
...
{r4, r5, r6, r7, r8, r9, sl, fp, ip, lr, pc}这 11 个寄存器都保存在栈中,指令“sub sp, sp, #16”
又使得栈向下扩展了 16 字节,所以本函数的栈大小为(11 × 4+16)字节,即 15 个双字。
栈信息开始部分的 15 个数据就是本函数的栈内容,下面列出了它们所保存的寄存器。
1e60:
c02b1f70 00000020 c03625d4 c036256c c036256c 00000000 c0389a3c
r4
r5
r6
1e80: c0389a3c c03c420c c0024864 00000000 c0481eac c0481ea0 c01bf4e8 c001a704
r7
r8
r9
sl
fp
ip
lr
pc
其中 lr 值为 c01bf4e8,表示函数 s3c2410fb_probe 执行完后的返回地址,它是调用函数
中的地址。下面使用 lr 值再次重复本步骤的回溯过程。
2 根据 lr 寄存器值找到调用函数,确定它的栈大小,确定上一级调用函数。
根据上步得到的 lr 值(c01bf4e8)在内核反汇编程序 vmlinux.dis 中可以知道它位于
platform_drv_probe 函数内。
根据这个函数开始部分的反汇编代码可以知道栈的大小、lr 返回值在栈中保存的位置。
代码如下:
c01bf4c8 <platform_drv_probe>:
c01bf4c8: e1a0c00d mov ip, sp
c01bf4cc: e92dd800 stmdb sp!, {fp, ip, lr, pc}
e89da800 ldmia sp, {fp, sp, pc}
...
c01bf4e8:
// lr 值(c01bf4e8)对应的指令
{fp, ip, lr, pc}这 4 寄存器都保存在栈中,本函数的栈大小为 4 个双字。Oops 栈信息中,
前一个函数 s3c2410fb_probe 的栈下面的 4 个数据就是函数 platform_drv_probe 的栈内容,如
下所示:
1ea0: c0481ed0 c0481eb0 c01bd5a8 c01bf4d8
fp
ip
lr
pc
其中 lr 值为 c01bd5a8,表示函数 platform_drv_probe 执行完后的返回地址,它是上一级
调用函数中的地址。使用 lr 值,重复本步骤的查找过程,直到栈信息分析完毕或者再也无法
分析,这样就可以找出所有的函数调用关系。
有些函数很简单,没有使用栈(sp 值在这个函数中没有变化)
,或者没有在栈中保存 lr
值。这些情况需要读者灵活处理,较强的汇编程序阅读能力是关键。

2020年2月11日 星期二

[轉錄] 每個人都是不理性的人?淺談常見的歸因謬誤,及其背後的意義

https://pansci.asia/archives/87359

每一天的生活當中,不論是在選舉前的議題辯論上、情侶的大小爭執上、課堂的討論課程上,往往可以看到爭執的雙方帶著「我的思考比較合理、理性」的態度和對方爭辯。但是,其實我們每個人的思考當中,總是充滿了許多可能的謬誤,事實上,我們也許永遠也無法看到客觀理性的事實,因為客觀理性的事實或許從來都不存在。

本篇文章將先舉出幾個常見的思考盲點,以及可能出現這些盲點的生活實例,最後,我將提出我的看法,討論看看我們是否能夠達成終極客觀的目標,或是我們只能在自己的主觀世界當中,探討各自認為的真實。
心理學家對於人們的思考謬誤,一直以來都充滿了興趣。就好像在一場球賽中,雙方的球迷總會看到不同的「真實」,例如今天剛結束的中華職棒台灣大賽,Lamigo和中信兄弟雙方的部分球迷,都帶著仇視對方球迷的觀點在批評對方的不是,認為是對方先秀下限,自己做的只是剛剛好而已。

事實上,Hastorf和Cantril兩位心理學家,在1954年所發表的一篇論文裡,就描述了這樣的現象:普林斯頓與達特茅斯兩校的美式足球校隊,在季後賽碰了頭,雙方球員在這場比賽中都相當粗暴,造成彼此衝突不斷、傷痕累累。球賽結束之後,心理學家們訪問了兩校的學生,播放了該球賽的影片給他們看,並要他們判斷雙方的犯規次數,幾乎所有普林斯頓的學生都認為這場球賽「粗暴而卑鄙」,認為對方的球員先開始了這場卑鄙的遊戲;但在此同時,達特茅斯的學生則認為雙方的責任相當,球賽雖然粗暴,但是公平而光明正大。同時,普林斯頓學生認為對手犯規次數是自己兩倍,但是達特茅斯的學生則認為雙方犯規次數差不多[1]。

心理學家把我們觀察的歷程稱為建構社會現實(construct social reality):我們會根據自身過去的經驗,對眼前的事件產生各自的認知與情感,並藉此建構各自的真實。也就是說,我們看待事情的方式,並不是來自於一個絕對客觀的標準,而是我們自身的經驗。由於我們都是根據各自的經驗來建構自身所看到的「真實」,因此難免會出錯,心理學家提出了幾種常見的歸因謬誤,最常見的便是基本歸因謬誤(fundamental attribution error),這是由心理學家Lee Ross在1977年所提出的,這種謬誤的定義是「在判斷某個人做出某件事情時,人們往往會高估性格因素的影響,而低估了環境的影響力」,尤其是在評判他人的事件時,這種歸因謬誤很常見,例如小明考試考不好,媽媽便認為是他自制力不夠,而沒有考量到老師的教學方式是否能夠引起他的興趣;同樣的,這種現象在政治口水戰上也很常見,例如有些人批評陳水扁總統任內經濟拉警報是他做得不好,卻沒有考量到當時全球的經濟脈動對我國經濟可能的影響。

還有一種常見的基本歸因謬誤,就是所謂的「公平世界假說(just world hypothesis)」[2]:「這個世界是公平的,那個女生半夜被強姦,一定是因為她穿著不檢點,半夜12點還穿熱褲走在暗巷裡,所以才會受害啦,不然其他人都沒有怎樣,為什麼就她被強姦?」,這便是一種常見的基本歸因謬誤,把錯誤過度歸咎於當事人的內在性格,而忽略了外在情境(如:犯罪本來就有可能是隨機發生的,治安不好應該要檢討的是巡邏網絡做得不夠徹底)。

其實公平世界假說的背後,其實也帶有著一種防衛性的思考,尤其當受害者和自己的特質、背景越相近的時候,人們越容易產生這樣子的思考模式:「如果她的特質跟我這麼像,我們都是住在同一個里裡面的人,她的年齡又和我相差不大,外貌也差不多,那麼她被強姦,我就也有可能被強姦」,當這樣想的時候,會讓自己感到很不安,畢竟這個環境不是我能掌控的,我也有可能在某一天遭受到襲擊。為了讓自己安心,不至於產生失調、焦慮的感受,於是當人們能夠把這件事情歸因於她的個性:「她穿著不檢點,所以才會被強姦」,而不是外在環境:「她運氣不好,事實上強姦案件是隨機發生的」,那麼思考者就能夠獲得一種安定的感受,認為自己不至於遭受和她相同的厄運。

最後,我們在思考自身的問題時,也很常採用自利偏誤(self-serving bias):好事情發生都是因為我夠努力(內在歸因),壞事情發生都是運氣不好(外在歸因)。但是當我們採取這樣的思考態度時,我們常常就沒辦法改變我們生活的模式,總是認為自己是不需要改變的,壞事的發生只是運氣不好而已,當我們越是這樣想時,就越難去正視自身可能的問題[3]。

然而,帶著這些歸因謬誤生存,真的是不好的嗎?又,這個世界上真的有客觀真實的存在嗎?我覺得可以採用諮商心理學常用的思考方式,來看待這樣的問題。我有一個朋友和他的諮商師討論,他是否應該繼續賭博,他的諮商師告訴他,如果賭博對他而言是一種生活中的娛樂,即使輸錢也不會造成他經濟上的負擔,但是不賭博卻會讓他沉溺在生活中的悲傷之中,那麼他繼續賭博反而是好事。這讓我想到佛洛伊德曾經說過的一句話:「如果某個人的自我防衛機轉有助於他生活下去,在你能夠為他提供更好的方式之前,請別剝奪他的防衛方式。」,也就是說,我們該不該正視自己的問題,重要的不是客觀而言,問題是不是真的是個問題,而是主觀而言,當我們做或不做某件事情時,對我們的影響是什麼?而我們想要怎麼樣的人生?

例如前面提到的公平世界假說,海苔熊便曾在江子翠捷運殺人事件發生之後,寫了一篇文章告訴讀者們,當我們遇到這樣的事情會有如此的恐慌,便是因為我們心中的公平世界假說崩壞了;這也就是說,當我們帶著這樣子的假說來看世界時,反而讓我們能夠更安心地去搭捷運,而不必因為某次的隨機事件,而對出門搭車這件事情感到過大的恐慌,否則我們根本沒有辦法繼續我們原本的生活。因此,雖然心理學家把這些思考方式稱為是謬誤,我覺得到不必然,因為這些思考方式,其實有時候是更有利於我們生存下去的。

進一步的探討這件事情,這個世界上真的有客觀真實的存在嗎?我覺得是值得懷疑的,因為每個人都有自己的思考模式,除了人們之外,並沒有一個更高階的思考主體,為這個世界訂定一個客觀的真實(我們暫時把神明等等放一邊)。但是,我覺得更重要的是,在這世界上,每一個人的主觀真實是確實存在的,每個人都有各自的思考、感受、行為、想法、生活經驗等等,當我們在探討所謂的歸因謬誤時,其實更應該從這樣的角度出發──我們所做的歸因,是否符合我們歸因對象的主觀真實世界?當我認為我女友總是自私自利,對我不公平時,這樣的想法,是否真的是她的本意,或是是我誤解了她的意思呢?從這樣的觀點作為思考的基礎,我覺得才是這些歸因謬誤理論,帶給我們最大的幫助吧!也許我們永遠無法覺察到所有人的主觀世界,但這些理論告訴了我們,其實我們所思考、感受的主觀世界,並不是如我們所以為的那麼絕對。
延伸閱讀