分类目录归档:伪技术

如何翻转图片

方法一: Numpy

import numpy as np
image_flipped_lr = np.fliplr(image) #水平翻转
image_flipped_ud = np.flipud(image) #上下翻转

参考资料:numpy.fliplr numpy.flipud

方法二: OpenCV

image_flipped = cv2.flip(image,1)

cv2.flip(src, flipCode[, dst]) → dst

参考资料:OpenCV

PS:设置 plt.imshow图片大小:

plt.figure(figsize=(15,5)) #设置图片显示大小
plt.subplot(1,2,1)
plt.imshow(image)
plt.subplot(1,2,2)
plt.imshow(image_flipped)

TypeError: __init__() missing 1 required positional argument: ‘nb_col’ 解决办法

当我第一次使用keras出现了:
TypeError: __init__() missing 1 required positional argument: ‘nb_col’ 的错误

经过搜索,发现原来是使用了旧版本的Keras,可以使用print(keras.__version__)查看版本号。

解决办法:
在conda下升级Keras:

conda install keras  

Conda 修改源 快速下载

自言自语:趁着现在在训练网络,在4月的最后一天,发表一篇文章。这篇很早之前就已经整理好了,只是迟迟未发表。最近发现当把神经网络移植到FPGA上时,速度居然没有GPU快。也是大跌眼镜了。本来认为可以拿奖的项目,突然又觉得希望渺茫~但项目做到这个地步,只能硬着头皮继续优化下去。(请忽略)


其实很简单,但是也没网上的教程那么简单。在实际中,仅通过命令行修改,并不一定能完全用修改后的源下载,还需要去修改配置文件。

首先设置命令:

conda config –add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ conda

config –set show_channel_urls yes

然后:需要修改conda的配置文件。删掉-default选项。

conda info -a 查看.condarc文件位置 修改

修改后,下载速度杠杠的!

参考资料:

https://mirrors.tuna.tsinghua.edu.cn/help/anaconda/

OpenCL for CodeBlock

这两个礼拜忙于项目。基于OpenCL的VGG-NET卷积神经网络。整个项目的思想很简单,但落实到具体细节上时,我和我队友折腾得焦头烂额。常常一想一个问题,就不舍得去做其他事。以至于放掉了很多计划中的事,包括very9s.net上发表文章,包括英语阅读。趁着现在,项目又进入一个新的问题,停滞不前时,休息下。发表篇文章。


在CodeBlock上搭建OpenCL环境

大部分在windows下的OpenCL环境都是基于visual studio IDE开发环境。其实现在我也是在Visual Studio 2015下进行OpenCL环境开发的。但是Visual studio对于初学者太过臃肿,且如果你是基于C语言开发的,那么Visual Studio支持并不是很好。所以我尝试过CodeBlock下开发,并且一切顺利。

下载时选择带有mingw包,能省去很多步骤。省得自己在配置编译环境。

创建OpenCL的编译器

C/C++ linking (gcc/g++)
    • In order to compile your OpenCL program you must tell the compiler to use the OpenCL library with the flag: –l OpenCL
    • If the compiler cannot find the OpenCL header files (it should do) you must specify the location of the CL/ folder with the –I (capital “i”) flag
    • If the linker cannot find the OpenCL runtime libraries (it should do) you must specify the location of the lib file with the –L flag
    • Make sure you are using a recent enough version of gcc/g++ – at least v4.7 is required to use the OpenCL C++ API (which needs C++11 support)

继续阅读

C语言指针理解

最近在做OpenCL的项目,做异构计算。在做的过程中让我不得不重新温习下C语言,不得不去深入理解指针的含义。下面几点我列出了我在《Beginning C:From Novice to Professional》(Ivor Horton)书中学到的几点关于C指针的内容。内容很浅显,但过了4年,重新理解这些简单的知识点,有许多新的体会。所谓大道至简,指针的魅力也许就在这些简单的定义,微小的细节当中。

1-指针是存储地址的变量。
2-编译器必须知道指针所指的变量类型。没有这个信息,就不知道如何处理所指向的内存内容。
3-void*类型的指针可以包含任意类型的地址。
4-未初始化的指针是非常危险的,所以应该在声明指针的时候对他进行初始化。例如:

int *pointer = NULL;
表示不指向任何内存的位置。NULL在多个头文件中都包含。例如stdio.h string.h等。NULL也相当于数字0的指针。即
int *pointer = 0;
与上面的初始化等价。
int *pointer = &number;
pointer变量中存储的是number的地址。
*pointer则是存储在number中的值。
*又称取消引用运算符。

5-可以改变指针指向的地址,因此同一个指针也可以改变不同内存空间里的值。
6-指向常量的指针:

const int *pointer = &value;
不能通过指针改变所指向的值。但可以直接对value进行操作。也可以改变指针指向的地址。

7-常量指针:

int *const pointer = &value;
指针存储的地址不能改变。但可以改变指针指向的内容。

8-指向常量的常量指针:

const int *const pointer = &item;
不能改变存储在指针中的地址,不能改变指向的内容。

 


指针与数组

1-指针和数组似乎完全不同,但他们有非常紧密的关系,有时候还可以互换。
2-数组和指针重要的区别:

可以改变指针包含的地址;
不能改变数组名称引用的地址。
(使用数组名称而不带索引值,就等于引用数组的第一个元素的地址)


动态内存分配

1-int *pointer = (int*)malloc(5*sizeof(int));

malloc是一般函数,可为任意类型的数据分配内存。因此这个函数并不知道要分配的内存空间要做什么用,所以返回的是一个void类型指针。因此要将返回的地址做类型转换。(int*)

2-int *pointer = (int*)calloc(5,sizeof(int));

calloc()函数与malloc()函数相比有两个优点:
-它把内存分配为给定大小的数组;
-它初始化了所分配的内存,所有位都是0;

3-释放动态内存:

动态内存,应在不需要改内存时释放他们。堆上分配的内存会在程序结束时自动释放,但是为了避免出现内存泄漏,应在使用完后释放内存,或者退出程序时释放内存。
free(pointer);
同时应避免两次释放相同的内存区域,因为这种情况下,free操作是不确定的,因此结果也是无法预料的。

DeepLearning:Linear Class解释

class Linear(Node):
    """
    Represents a node that performs a linear transform.
    """
    def __init__(self, X, W, b):
        # The base class (Node) constructor. Weights and bias
        # are treated like inbound nodes.
        Node.__init__(self, [X, W, b])

    def forward(self):
        """
        Performs the math behind a linear transform.
        """
        X = self.inbound_nodes[0].value
        W = self.inbound_nodes[1].value
        b = self.inbound_nodes[2].value
        self.value = np.dot(X, W) + b

    def backward(self):
        """
        Calculates the gradient based on the output values.
        """
        # Initialize a partial for each of the inbound_nodes.
        self.gradients = {n: np.zeros_like(n.value) for n in self.inbound_nodes}
        # Cycle through the outputs. The gradient will change depending
        # on each output, so the gradients are summed over all outputs.
        for n in self.outbound_nodes:
            # Get the partial of the cost with respect to this node.
            grad_cost = n.gradients[self]
            # Set the partial of the loss with respect to this node's inputs.
            self.gradients[self.inbound_nodes[0]] += np.dot(grad_cost, self.inbound_nodes[1].value.T)
            # Set the partial of the loss with respect to this node's weights.
            self.gradients[self.inbound_nodes[1]] += np.dot(self.inbound_nodes[0].value.T, grad_cost)
            # Set the partial of the loss with respect to this node's bias.
            self.gradients[self.inbound_nodes[2]] += np.sum(grad_cost, axis=0, keepdims=False)

1. the loss with respect to inputs
self.gradients[self.inbound_nodes[0]] += np.dot(grad_cost, self.inbound_nodes[1].value.T)
Cost对某个Node的导数(gradient)等于Cost对前面节点导数的乘积。

解释一:

np.dot(grad_cost, self.inbound_nodes[1].value.T)

对于Linear节点来说,有三个输入参数,即inputs, weights, bias分别对应着

self.inbound_nodes[0],self.inbound_nodes[1],self.inbound_nodes[2]

So, each node will pass on the cost gradient to its inbound nodes and each node will get the cost gradient from it’s outbound nodes. Then, for each node we’ll need to calculate a gradient that’s the cost gradient times the gradient of that node with respect to its inputs.

于是Linear对inputs的求导就是weights。所以是grad_cost*weights.grad_cost是Linear输出节点传递进来的变化率。

np.dot(self.inbound_nodes[0].value.T, grad_cost)

同理可推对weights的求导为inputs,于是gradient=grad_cost*inputs

np.sum(grad_cost, axis=0, keepdims=False)

而对于bias,Linear对bias求导恒为1.所以gradient=1*grad_cost

解释二:为何是+=

因为每一个节点将误差传递给每一个输出节点。于是在Backpropagation时,要求出每一个节点的误差,就要将每一份传递出去给输出节点的误差加起来。于是用+=。
于是可以理解为什么要for n in self.outbound_nodes: 目的是为了在每一个节点的输出节点里遍历。
If a node has multiple outgoing nodes, you just sum up the gradients from each node.

注意点一:
要区分Backpropagation 和Gradient Descent是两个步骤,我通过Backpropagation找到gradient,于是找到了变化方向。再通过Gradient Descent来最小化误差。

To find the gradient, you just multiply the gradients for all nodes in front of it going backwards from the cost. This is the idea behind backpropagation. The gradients are passed backwards through the network and used with gradient descent to update the weights and biases.

最终目的是:

Backpropagation只求了导数部分。Gradient Descent则是整个过程。