Socket编程:解决发送与接收数据不全

这个问题是在上个月在做的项目中遇到的问题。项目采用分布式计算,通过网线传输数据。然而却发现用Socket接收和发送数据会出现不全的问题。由于是第一次使用Socket,因此这个问题还是费了点时间去解决。现在把它整理下。


客户端
原来的编程方案:(错误)

//创建套接字
int sock = socket(AF_INET, SOCK_STREAM, 0);
//向服务器(特定的IP和端口)发起请求
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));  //每个字节都用0填充
serv_addr.sin_family = AF_INET;  //使用IPv4地址
serv_addr.sin_addr.s_addr = inet_addr("169.254.48.205");  //具体的IP地址
serv_addr.sin_port = htons(1234);  //端口
connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
//向服务器发送数据
printf("Sending...\n");
write(sock, (char*)conv_ouput, sizeof(float) * 25088);
printf("Send Successful\n");
//关闭套接字
close(sock);

这里有个问题,即是发送端不能保证一次性全部发完数据。因此必须确保发送到能够发全数据。

修改后的编程方案:(正确)

int sock = socket(AF_INET, SOCK_STREAM, 0);
//向服务器(特定的IP和端口)发起请求
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));  //每个字节都用0填充
serv_addr.sin_family = AF_INET;  //使用IPv4地址
serv_addr.sin_addr.s_addr = inet_addr("169.254.48.205");  //具体的IP地址
serv_addr.sin_port = htons(1234);  //端口
connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
//向服务器发送数据
printf("Sending...\n");
int pos = 0;
while(pos < 25088*sizeof(float))
{
	int send_num = send(sock,(char*)conv_ouput+pos, sizeof(float) * 25088, 0);
	if(send_num<=0)
	{
		break;
		printf("send error\n");
	}
	pos += send_num;
}
printf("send num = %d\n",pos);
printf("Send Successful\n");
//关闭套接字
close(sock);

继续阅读

中科院offer!!!

我从来也没有想到我能去中科院实习。周二我在实习僧上看到中科院在招聘实习,于是抱着试试的态度发了简历,没想到第二天就电话面试,面试还很顺利。也就问我现在在做的项目,最后竟然直接说:”那我给你发offer吧~“。真的是把我高兴坏了~真的是高兴坏了~高兴得我把正在睡午觉的舍友摇醒~跟他分享喜悦。第一时间告诉了老爸,姐姐。这两天渐渐平静下来了。

终于要出远门了!从高考后就一心想着考出省,去外面看看。然而现实是在省内选个一本院校容易,在省外选好学校就有可能上不了。于是大学继续省内读书,其实是市内读书。接着就是考研。也是选择离家一千公里的学校,不过最后也是没成。不过我总是能接受现实,于是又留在了市内读研。

现在终于有机会了。但现在的我,就好像一个在浅水区游惯的人,突然到海里去游泳一样。心里有一种巨大的压力感,是对陌生水域的恐惧。

不过人生就是这样,一步一步的往前迈。

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则是整个过程。

 

解决defaults::qt-5.6.2-vc14_3

使用conda 安装tensorflow的时候,出现了这个问题,这不是第一次的出现了。上一次出现,我选择重新安装miniconda,问题解决了。这次我决定去解决他!

ERROR conda.core.link:_execute_actions(330): An error occurred while installing package ‘defaults::qt-5.6.2-vc14_3’. UnicodeDecodeError(‘utf-8′, b’\xd2\xd1\xb8\xb4\xd6\xc6 1 \xb8\xf6\xce\xc4\xbc\xfe\xa1\xa3\r\n‘, 0, 1, ‘invalid continuation byte’) Attempting to roll back. UnicodeDecodeError(‘utf-8′, b’\xd2\xd1\xb8\xb4\xd6\xc6 1 \xb8\xf6\xce\xc4\xbc\xfe\xa1\xa3\r\n‘, 0, 1, ‘invalid continuation byte’)

ERROR conda.core.link:_execute_actions(319): An error occurred while installing package ‘defaults::qt-5.6.2-vc9_3’

python | 解决defaults::qt-5.6.2-vc14_3

这两篇都是同一种解决方法,但是当我试着他们的方法的时候,却出现了新的问题,即ModuleNotFoundError: No module named ‘chardet’

于是我直接用conda在root环境下安装chardet

conda install chardet
最后一切搞定,连上面两篇文章的添加内容都不需要~

笔记本升级SSD

电脑莫名其妙总是蓝屏!一气之下,买了固态硬盘。好在主板只有SATA2的接口,所以正好可以省点钱,买低配的SSD。但是也要500大洋,心疼。不过念在学校又发了1000大洋,想想这台12年高考毕业时买的古董,也算焕发第三春了。

大概是大二的时候,升级了内存。加了一条4G内存。这是第二春(ಡωಡ)hiahiahia

没什么事做,尝试用手机发表文章,试试效果。除了屏幕小以外,其他都可以接受。

作为小白,为了选购SSD还特意去看了知乎相关回答,涨了不少知识。

【如何选购固态硬盘?】dyoule:https://www.zhihu.com/question/20369676/answer/99405990?utm_source=com.meizu.notepaper&utm_medium=social (分享自知乎网)

Very9s第二年

很高兴坚持留下来。最近比较忙,所以写的比较少。但是素材准备了很多。等过段时间,整理整理,写出来。

最近为了自己的项目,焦头烂额的。亚历山大~~不想多说了,有机会再写吧~


2017.5.20添:

删除放在github上的旧站。为了以后还能怀念她,截了首页的图。

这个主题还是我仿照lofter上的主题自己做的。花了可能有一周的时间。好不舍得。

射频工程师的爱情诗

射频工程师的爱情诗
佚名

我在时域
你在频域
需要经过傅立叶变换
才能发现你的美丽
我把爱的语言调制到星座
通过伪随机序列
载波到到你的频率
并波束赋形到你的接收阵列矩阵
你说我的爱噪声太大
经过层层滤波
原来发现
那是在宇宙开始的时候
我发给你的爱的微波背景辐射
两百年前粗略的论断
催生傅立叶变换不朽的缠绵

继续阅读